diff --git a/CHANGELOG.md b/CHANGELOG.md index e10aaec5..e722c80a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,45 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +## Changed + +- SCEX filename updates. Also use T as the file ID / date separator between date and time. +- COM TM store and dump handling: Introduce modes for all 4 TM VC/store tasks. The OFF mode can be + used to disable ongoing dumps or to prevent writes to the PTME VC. This allows cleaner reset + handling of the PTME. All 4 VC/store tasks were attached to the COM mode tree and are commanded + as part of the COM sequence as well to ensure consistent state with the CCSDS IP core handler. +- Added `PTME_LOCKED` boolean lock which is used to lock the PTME so it is not used by the VC tasks + anymore. This lock will be controlled by the CCSDS IP core handler and is locked when the PTME + needs to be reset. Examples for this are datarate changes. + +## Fixed + +- Bugfix for side lane transitions of the dual lane assemblies, which only worked when the + assembly was directly commanded +- Syrlinks Handler: Bugfix so transition command is only sent once. + +## Added + +- Added GPS0 and GPS1 health device which are used by the ACS board assembly when deciding whether + to change to the other side or to go to dual side directly. Setting the health devices to faulty + should also trigger a side switch or a switch to dual mode. + +# [v1.41.0] 2023-03-28 + +eive-tmtc: v2.20.0 +q7s-package: v2.2.0 + ## Fixed - Proper Faulty/External Control handling for the dual lane assemblies. - ACS board devices: Go to ON mode instead of going to NORMAL mode directly. - SUS device handlers: Go to ON mode on startup instead of NORMAL mode. +- Tweaks for the delay handling for the persistent TM stores. This allows pushing the full + high datarate when dumping telemetry. The most important and interesting fix is that + there needs to be a small delay between the polling of the GPIO. Polling the GPIO + without any delay consecutively can lead to scheduling issues. +- Bump FSFW for fix of `ControllerBase` class `startTransition` implementation. +- Bump FSFW for possible fix of `PowerSwitcherComponent`: Initial mode `MODE_UNDEFINED`. ## Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index c71f8360..3a2842a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.13) set(OBSW_VERSION_MAJOR 1) -set(OBSW_VERSION_MINOR 40) +set(OBSW_VERSION_MINOR 41) set(OBSW_VERSION_REVISION 0) # set(CMAKE_VERBOSE TRUE) @@ -486,7 +486,8 @@ endif() target_link_libraries(${LIB_EIVE_MISSION} PUBLIC ${LIB_FSFW_NAME} ${LIB_OS_NAME}) -target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_FSFW_NAME} ${LIB_JSON_NAME}) +target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_EIVE_MISSION} + ${LIB_FSFW_NAME} ${LIB_JSON_NAME}) target_link_libraries(${OBSW_NAME} PRIVATE ${LIB_EIVE_MISSION} ${LIB_DUMMIES}) diff --git a/bsp_hosted/ObjectFactory.cpp b/bsp_hosted/ObjectFactory.cpp index 28060afd..3d618cdb 100644 --- a/bsp_hosted/ObjectFactory.cpp +++ b/bsp_hosted/ObjectFactory.cpp @@ -30,7 +30,7 @@ #include #include -#include "dummies/helpers.h" +#include "dummies/helperFactory.h" #ifdef PLATFORM_UNIX #include diff --git a/bsp_hosted/fsfwconfig/events/translateEvents.cpp b/bsp_hosted/fsfwconfig/events/translateEvents.cpp index 38224ad6..8bce9e73 100644 --- a/bsp_hosted/fsfwconfig/events/translateEvents.cpp +++ b/bsp_hosted/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 278 translations. + * @brief Auto-generated event translation file. Contains 284 translations. * @details - * Generated on: 2023-03-26 16:47:32 + * Generated on: 2023-03-31 19:17:49 */ #include "translateEvents.h" @@ -209,11 +209,11 @@ const char *TRANSITION_OTHER_SIDE_FAILED_STRING = "TRANSITION_OTHER_SIDE_FAILED" const char *NOT_ENOUGH_DEVICES_DUAL_MODE_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE"; const char *POWER_STATE_MACHINE_TIMEOUT_STRING = "POWER_STATE_MACHINE_TIMEOUT"; const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING = "SIDE_SWITCH_TRANSITION_NOT_ALLOWED"; +const char *DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING = "DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY"; const char *TRANSITION_OTHER_SIDE_FAILED_12900_STRING = "TRANSITION_OTHER_SIDE_FAILED_12900"; const char *NOT_ENOUGH_DEVICES_DUAL_MODE_12901_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE_12901"; const char *POWER_STATE_MACHINE_TIMEOUT_12902_STRING = "POWER_STATE_MACHINE_TIMEOUT_12902"; -const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903_STRING = - "SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903"; +const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903_STRING = "SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903"; const char *CHILDREN_LOST_MODE_STRING = "CHILDREN_LOST_MODE"; const char *GPS_FIX_CHANGE_STRING = "GPS_FIX_CHANGE"; const char *CANT_GET_FIX_STRING = "CANT_GET_FIX"; @@ -273,17 +273,22 @@ const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING"; const char *OBC_OVERHEATING_STRING = "OBC_OVERHEATING"; const char *CAMERA_OVERHEATING_STRING = "CAMERA_OVERHEATING"; const char *PCDU_SYSTEM_OVERHEATING_STRING = "PCDU_SYSTEM_OVERHEATING"; +const char *HEATER_NOT_OFF_FOR_OFF_MODE_STRING = "HEATER_NOT_OFF_FOR_OFF_MODE"; const char *TX_TIMER_EXPIRED_STRING = "TX_TIMER_EXPIRED"; const char *BIT_LOCK_TX_ON_STRING = "BIT_LOCK_TX_ON"; const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION"; const char *FILE_TOO_LARGE_STRING = "FILE_TOO_LARGE"; const char *BUSY_DUMPING_EVENT_STRING = "BUSY_DUMPING_EVENT"; -const char *DUMP_WAS_CANCELLED_STRING = "DUMP_WAS_CANCELLED"; const char *DUMP_OK_STORE_DONE_STRING = "DUMP_OK_STORE_DONE"; const char *DUMP_NOK_STORE_DONE_STRING = "DUMP_NOK_STORE_DONE"; const char *DUMP_MISC_STORE_DONE_STRING = "DUMP_MISC_STORE_DONE"; const char *DUMP_HK_STORE_DONE_STRING = "DUMP_HK_STORE_DONE"; const char *DUMP_CFDP_STORE_DONE_STRING = "DUMP_CFDP_STORE_DONE"; +const char *DUMP_OK_CANCELLED_STRING = "DUMP_OK_CANCELLED"; +const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED"; +const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED"; +const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED"; +const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED"; const char *translateEvents(Event event) { switch ((event & 0xFFFF)) { @@ -695,6 +700,8 @@ const char *translateEvents(Event event) { return POWER_STATE_MACHINE_TIMEOUT_STRING; case (12803): return SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING; + case (12804): + return DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING; case (12900): return TRANSITION_OTHER_SIDE_FAILED_12900_STRING; case (12901): @@ -821,6 +828,8 @@ const char *translateEvents(Event event) { return CAMERA_OVERHEATING_STRING; case (14106): return PCDU_SYSTEM_OVERHEATING_STRING; + case (14107): + return HEATER_NOT_OFF_FOR_OFF_MODE_STRING; case (14201): return TX_TIMER_EXPIRED_STRING; case (14202): @@ -831,8 +840,6 @@ const char *translateEvents(Event event) { return FILE_TOO_LARGE_STRING; case (14302): return BUSY_DUMPING_EVENT_STRING; - case (14303): - return DUMP_WAS_CANCELLED_STRING; case (14305): return DUMP_OK_STORE_DONE_STRING; case (14306): @@ -843,6 +850,16 @@ const char *translateEvents(Event event) { return DUMP_HK_STORE_DONE_STRING; case (14309): return DUMP_CFDP_STORE_DONE_STRING; + case (14310): + return DUMP_OK_CANCELLED_STRING; + case (14311): + return DUMP_NOK_CANCELLED_STRING; + case (14312): + return DUMP_MISC_CANCELLED_STRING; + case (14313): + return DUMP_HK_CANCELLED_STRING; + case (14314): + return DUMP_CFDP_CANCELLED_STRING; default: return "UNKNOWN_EVENT"; } diff --git a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp index 388ecd55..173c476b 100644 --- a/bsp_hosted/fsfwconfig/objects/translateObjects.cpp +++ b/bsp_hosted/fsfwconfig/objects/translateObjects.cpp @@ -1,8 +1,8 @@ /** * @brief Auto-generated object translation file. * @details - * Contains 169 translations. - * Generated on: 2023-03-26 16:47:32 + * Contains 171 translations. + * Generated on: 2023-03-31 19:17:49 */ #include "translateObjects.h" @@ -38,6 +38,8 @@ const char *GYRO_3_L3G_HANDLER_STRING = "GYRO_3_L3G_HANDLER"; const char *RW4_STRING = "RW4"; const char *STAR_TRACKER_STRING = "STAR_TRACKER"; const char *GPS_CONTROLLER_STRING = "GPS_CONTROLLER"; +const char *GPS_0_HEALTH_DEV_STRING = "GPS_0_HEALTH_DEV"; +const char *GPS_1_HEALTH_DEV_STRING = "GPS_1_HEALTH_DEV"; const char *IMTQ_POLLING_STRING = "IMTQ_POLLING"; const char *IMTQ_HANDLER_STRING = "IMTQ_HANDLER"; const char *PCDU_HANDLER_STRING = "PCDU_HANDLER"; @@ -242,6 +244,10 @@ const char *translateObject(object_id_t object) { return STAR_TRACKER_STRING; case 0x44130045: return GPS_CONTROLLER_STRING; + case 0x44130046: + return GPS_0_HEALTH_DEV_STRING; + case 0x44130047: + return GPS_1_HEALTH_DEV_STRING; case 0x44140013: return IMTQ_POLLING_STRING; case 0x44140014: diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index bbfa4c8a..dea4a675 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -1,5 +1,6 @@ #include "ObjectFactory.h" +#include #include #include #include @@ -19,15 +20,15 @@ #include #include #include +#include +#include +#include #include #include +#include #include #include -#include #include -#include -#include -#include #include "OBSWConfig.h" #include "bsp_q7s/boardtest/Q7STestTask.h" @@ -80,6 +81,7 @@ using gpio::Levels; #include #include #include +#include #include #include #include @@ -95,7 +97,6 @@ using gpio::Levels; #include #include #include -#include #include @@ -124,6 +125,7 @@ using gpio::Levels; ResetArgs RESET_ARGS_GNSS; std::atomic_bool LINK_STATE = CcsdsIpCoreHandler::LINK_DOWN; +std::atomic_bool PTME_LOCKED = false; std::atomic_uint16_t I2C_FATAL_ERRORS = 0; void Factory::setStaticFrameworkObjectIds() { @@ -516,6 +518,8 @@ void ObjectFactory::createAcsBoardComponents(SpiComIF& spiComIF, LinuxLibgpioIF* new GpsHyperionLinuxController(objects::GPS_CONTROLLER, objects::NO_OBJECT, debugGps); gpsCtrl->setResetPinTriggerFunction(gps::triggerGpioResetPin, &RESET_ARGS_GNSS); + new HealthDevice(objects::GPS_0_HEALTH_DEV, objects::ACS_BOARD_ASS); + new HealthDevice(objects::GPS_1_HEALTH_DEV, objects::ACS_BOARD_ASS); ObjectFactory::createAcsBoardAssy(pwrSwitcher, assemblyChildren, gpsCtrl, gpioComIF); #endif /* OBSW_ADD_ACS_HANDLERS == 1 */ } @@ -751,10 +755,8 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio); gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, "PAPB VC3"); gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio); - // Initialise to low and then pull high to do a PTME reset, which puts the PTME in reset - // state. It will be put out of reset in the CCSDS handler initialize function. gpio = new GpiodRegularByLineName(q7s::gpioNames::PTME_RESETN, "PTME RESETN", - gpio::Direction::OUT, gpio::Levels::LOW); + gpio::Direction::OUT, gpio::Levels::HIGH); gpioCookiePtmeIp->addGpio(gpioIds::PTME_RESETN, gpio); gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs"); @@ -788,34 +790,42 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) { *args.ipCoreHandler = new CcsdsIpCoreHandler(objects::CCSDS_HANDLER, objects::CCSDS_PACKET_DISTRIBUTOR, *ptmeConfig, - LINK_STATE, &args.gpioComIF, gpios); + LINK_STATE, &args.gpioComIF, gpios, PTME_LOCKED); // This VC will receive all live TM auto* vcWithQueue = new VirtualChannelWithQueue(objects::PTME_VC0_LIVE_TM, ccsds::VC0, "PTME VC0 LIVE TM", *ptme, LINK_STATE, args.tmStore, 500); args.liveDestination = vcWithQueue; - new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, *vcWithQueue); + auto* liveTask = new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, + *vcWithQueue, PTME_LOCKED); + liveTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); // Set up log store. auto* vc = new VirtualChannel(objects::PTME_VC1_LOG_TM, ccsds::VC1, "PTME VC1 LOG TM", *ptme, LINK_STATE); LogStores logStores(args.stores); // Core task which handles the LOG store and takes care of dumping it as TM using a VC directly - new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc, - *SdCardManager::instance()); + auto* logStore = + new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc, + *SdCardManager::instance(), PTME_LOCKED); + logStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC2_HK_TM, ccsds::VC2, "PTME VC2 HK TM", *ptme, LINK_STATE); // Core task which handles the HK store and takes care of dumping it as TM using a VC directly - new PersistentSingleTmStoreTask(objects::HK_STORE_AND_TM_TASK, args.ipcStore, - *args.stores.hkStore, *vc, persTmStore::DUMP_HK_STORE_DONE, - *SdCardManager::instance()); + auto* hkStore = new PersistentSingleTmStoreTask( + objects::HK_STORE_AND_TM_TASK, args.ipcStore, *args.stores.hkStore, *vc, + persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance(), + PTME_LOCKED); + hkStore->connectModeTreeParent(satsystem::com::SUBSYSTEM); vc = new VirtualChannel(objects::PTME_VC3_CFDP_TM, ccsds::VC3, "PTME VC3 CFDP TM", *ptme, LINK_STATE); // Core task which handles the CFDP store and takes care of dumping it as TM using a VC directly - new PersistentSingleTmStoreTask(objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, - *args.stores.cfdpStore, *vc, persTmStore::DUMP_CFDP_STORE_DONE, - *SdCardManager::instance()); + auto* cfdpTask = new PersistentSingleTmStoreTask( + objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, *args.stores.cfdpStore, *vc, + persTmStore::DUMP_CFDP_STORE_DONE, persTmStore::DUMP_CFDP_CANCELLED, + *SdCardManager::instance(), PTME_LOCKED); + cfdpTask->connectModeTreeParent(satsystem::com::SUBSYSTEM); ReturnValue_t result = (*args.ipCoreHandler)->connectModeTreeParent(satsystem::com::SUBSYSTEM); if (result != returnvalue::OK) { diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h index dc65e1f4..b7380f2a 100644 --- a/bsp_q7s/core/ObjectFactory.h +++ b/bsp_q7s/core/ObjectFactory.h @@ -4,11 +4,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include @@ -24,6 +24,7 @@ class AcsBoardAssembly; class GpioIF; extern std::atomic_uint16_t I2C_FATAL_ERRORS; +extern std::atomic_bool PTME_LOCKED; namespace ObjectFactory { diff --git a/bsp_q7s/core/scheduling.cpp b/bsp_q7s/core/scheduling.cpp index 25f8ede4..2d767687 100644 --- a/bsp_q7s/core/scheduling.cpp +++ b/bsp_q7s/core/scheduling.cpp @@ -291,6 +291,14 @@ void scheduling::initTasks() { if (result != returnvalue::OK) { scheduling::printAddObjectError("STR_ASSY", objects::STR_ASSY); } + result = acsSysTask->addComponent(objects::GPS_0_HEALTH_DEV); + if (result != returnvalue::OK) { + scheduling::printAddObjectError("GPS_0_HEALTH_DEV", objects::GPS_0_HEALTH_DEV); + } + result = acsSysTask->addComponent(objects::GPS_1_HEALTH_DEV); + if (result != returnvalue::OK) { + scheduling::printAddObjectError("GPS_1_HEALTH_DEV", objects::GPS_1_HEALTH_DEV); + } PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask( "TCS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING); diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index c0852c05..1f873b99 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -13,7 +13,7 @@ #include "bsp_q7s/core/ObjectFactory.h" #include "busConf.h" #include "devConf.h" -#include "dummies/helpers.h" +#include "dummies/helperFactory.h" #include "eive/objects.h" #include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h" #include "linux/ObjectFactory.h" diff --git a/common/config/eive/objects.h b/common/config/eive/objects.h index 667067bb..0cc4b9d9 100644 --- a/common/config/eive/objects.h +++ b/common/config/eive/objects.h @@ -43,6 +43,8 @@ enum commonObjects : uint32_t { RW4 = 0x44120350, STAR_TRACKER = 0x44130001, GPS_CONTROLLER = 0x44130045, + GPS_0_HEALTH_DEV = 0x44130046, + GPS_1_HEALTH_DEV = 0x44130047, IMTQ_POLLING = 0x44140013, IMTQ_HANDLER = 0x44140014, diff --git a/dummies/CMakeLists.txt b/dummies/CMakeLists.txt index 75dd1364..6a49fcc6 100644 --- a/dummies/CMakeLists.txt +++ b/dummies/CMakeLists.txt @@ -26,6 +26,6 @@ target_sources( CoreControllerDummy.cpp PlocMpsocDummy.cpp PlocSupervisorDummy.cpp - helpers.cpp + helperFactory.cpp MgmRm3100Dummy.cpp Tmp1075Dummy.cpp) diff --git a/dummies/helpers.cpp b/dummies/helperFactory.cpp similarity index 97% rename from dummies/helpers.cpp rename to dummies/helperFactory.cpp index 1056cb35..703683f4 100644 --- a/dummies/helpers.cpp +++ b/dummies/helperFactory.cpp @@ -1,4 +1,4 @@ -#include "helpers.h" +#include "helperFactory.h" #include #include @@ -24,11 +24,12 @@ #include #include #include +#include #include #include #include +#include #include -#include #include #include "TemperatureSensorInserter.h" @@ -98,6 +99,8 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio new GyroAdisDummy(objects::GYRO_2_ADIS_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); assemblyDhbs[7] = new GyroL3GD20Dummy(objects::GYRO_3_L3G_HANDLER, objects::DUMMY_COM_IF, comCookieDummy); + new HealthDevice(objects::GPS_0_HEALTH_DEV, objects::ACS_BOARD_ASS); + new HealthDevice(objects::GPS_1_HEALTH_DEV, objects::ACS_BOARD_ASS); auto* gpsCtrl = new GpsCtrlDummy(objects::GPS_CONTROLLER); ObjectFactory::createAcsBoardAssy(pwrSwitcher, assemblyDhbs, gpsCtrl, gpioIF); } diff --git a/dummies/helpers.h b/dummies/helperFactory.h similarity index 100% rename from dummies/helpers.h rename to dummies/helperFactory.h diff --git a/generators/bsp_hosted_events.csv b/generators/bsp_hosted_events.csv index 086cadc3..d7265738 100644 --- a/generators/bsp_hosted_events.csv +++ b/generators/bsp_hosted_events.csv @@ -203,6 +203,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 12801;0x3201;NOT_ENOUGH_DEVICES_DUAL_MODE;HIGH;No description;mission/system/acs/AcsBoardAssembly.h 12802;0x3202;POWER_STATE_MACHINE_TIMEOUT;MEDIUM;No description;mission/system/acs/AcsBoardAssembly.h 12803;0x3203;SIDE_SWITCH_TRANSITION_NOT_ALLOWED;LOW;Not implemented, would increase already high complexity. Operator should instead command the assembly off first and then command the assembly on into the desired mode/submode combination;mission/system/acs/AcsBoardAssembly.h +12804;0x3204;DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY;MEDIUM;This is triggered when the assembly would have normally switched the board side, but the GPS device of the other side was marked faulty. P1: Current submode.;mission/system/acs/AcsBoardAssembly.h 12900;0x3264;TRANSITION_OTHER_SIDE_FAILED;HIGH;No description;mission/system/acs/SusAssembly.h 12901;0x3265;NOT_ENOUGH_DEVICES_DUAL_MODE;HIGH;No description;mission/system/acs/SusAssembly.h 12902;0x3266;POWER_STATE_MACHINE_TIMEOUT;MEDIUM;No description;mission/system/acs/SusAssembly.h @@ -266,14 +267,19 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 14104;0x3718;OBC_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h 14105;0x3719;CAMERA_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h 14106;0x371a;PCDU_SYSTEM_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h +14107;0x371b;HEATER_NOT_OFF_FOR_OFF_MODE;MEDIUM;No description;mission/controller/tcsDefs.h 14201;0x3779;TX_TIMER_EXPIRED;INFO;The transmit timer to protect the Syrlinks expired P1: The current timer value;mission/system/com/ComSubsystem.h 14202;0x377a;BIT_LOCK_TX_ON;INFO;Transmitter will be turned on due to detection of bitlock;mission/system/com/ComSubsystem.h 14300;0x37dc;POSSIBLE_FILE_CORRUPTION;LOW;P1: Result code of TM packet parser. P2: Timestamp of possibly corrupt file as a unix timestamp.;mission/persistentTmStoreDefs.h 14301;0x37dd;FILE_TOO_LARGE;LOW;File in store too large. P1: Detected file size P2: Allowed file size;mission/persistentTmStoreDefs.h 14302;0x37de;BUSY_DUMPING_EVENT;INFO;No description;mission/persistentTmStoreDefs.h -14303;0x37df;DUMP_WAS_CANCELLED;LOW;Dump was cancelled. P1: Object ID of store.;mission/persistentTmStoreDefs.h 14305;0x37e1;DUMP_OK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14306;0x37e2;DUMP_NOK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14307;0x37e3;DUMP_MISC_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14308;0x37e4;DUMP_HK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14309;0x37e5;DUMP_CFDP_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14310;0x37e6;DUMP_OK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14311;0x37e7;DUMP_NOK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14312;0x37e8;DUMP_MISC_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14313;0x37e9;DUMP_HK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14314;0x37ea;DUMP_CFDP_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h diff --git a/generators/bsp_hosted_objects.csv b/generators/bsp_hosted_objects.csv index a30fc9d8..3faac37c 100644 --- a/generators/bsp_hosted_objects.csv +++ b/generators/bsp_hosted_objects.csv @@ -30,6 +30,8 @@ 0x44120350;RW4 0x44130001;STAR_TRACKER 0x44130045;GPS_CONTROLLER +0x44130046;GPS_0_HEALTH_DEV +0x44130047;GPS_1_HEALTH_DEV 0x44140013;IMTQ_POLLING 0x44140014;IMTQ_HANDLER 0x442000A1;PCDU_HANDLER diff --git a/generators/bsp_hosted_returnvalues.csv b/generators/bsp_hosted_returnvalues.csv index 09429179..dc960aa3 100644 --- a/generators/bsp_hosted_returnvalues.csv +++ b/generators/bsp_hosted_returnvalues.csv @@ -291,8 +291,8 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x2e02;HPA_InvalidDomainId;No description;2;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h 0x2e03;HPA_InvalidValue;No description;3;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h 0x2e05;HPA_ReadOnly;No description;5;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h -0x2f01;ASC_NoPacketFound;No description;1;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/DleParser.h -0x2f02;ASC_PossiblePacketLoss;No description;2;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/DleParser.h +0x2f01;ASC_TooLongForTargetType;No description;1;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h +0x2f02;ASC_InvalidCharacters;No description;2;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h 0x2f03;ASC_BufferTooSmall;No description;3;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h 0x3001;POS_InPowerTransition;No description;1;POWER_SWITCHER;fsfw/src/fsfw/power/PowerSwitcher.h 0x3002;POS_SwitchStateMismatch;No description;2;POWER_SWITCHER;fsfw/src/fsfw/power/PowerSwitcher.h @@ -371,8 +371,8 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x3e03;HKM_PeriodicHelperInvalid;No description;3;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h 0x3e04;HKM_PoolobjectNotFound;No description;4;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h 0x3e05;HKM_DatasetNotFound;No description;5;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h -0x3f01;DLEE_StreamTooShort;No description;1;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h -0x3f02;DLEE_DecodingError;No description;2;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h +0x3f01;DLEE_NoPacketFound;No description;1;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleParser.h +0x3f02;DLEE_PossiblePacketLoss;No description;2;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleParser.h 0x4201;PUS11_InvalidTypeTimeWindow;No description;1;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h 0x4202;PUS11_InvalidTimeWindow;No description;2;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h 0x4203;PUS11_TimeshiftingNotPossible;No description;3;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h @@ -402,9 +402,9 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x4403;UXOS_CommandError;Command execution failed;3;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h 0x4404;UXOS_NoCommandLoadedOrPending;;4;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h 0x4406;UXOS_PcloseCallError;No description;6;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h -0x4500;HSPI_HalTimeoutRetval;No description;0;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h -0x4501;HSPI_HalBusyRetval;No description;1;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h -0x4502;HSPI_HalErrorRetval;No description;2;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h +0x4500;HSPI_OpeningFileFailed;No description;0;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h +0x4501;HSPI_FullDuplexTransferFailed;No description;1;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h +0x4502;HSPI_HalfDuplexTransferFailed;No description;2;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h 0x4601;HURT_UartReadFailure;No description;1;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h 0x4602;HURT_UartReadSizeMissmatch;No description;2;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h 0x4603;HURT_UartRxBufferTooSmall;No description;3;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h @@ -415,12 +415,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x4805;HGIO_GpioDuplicateDetected;No description;5;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h 0x4806;HGIO_GpioInitFailed;No description;6;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h 0x4807;HGIO_GpioGetValueFailed;No description;7;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h -0x4aa0;MGMLIS3_InvalidSpeed;Action Message with invalid speed was received. Valid speeds must be in the range of [-65000, 1000] or [1000, 65000];160;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa1;MGMLIS3_InvalidRampTime;Action Message with invalid ramp time was received.;161;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa2;MGMLIS3_SetSpeedCommandInvalidLength;Received set speed command has invalid length. Should be 6.;162;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa3;MGMLIS3_ExecutionFailed;Command execution failed;163;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa4;MGMLIS3_CrcError;Reaction wheel reply has invalid crc;164;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa5;MGMLIS3_ValueNotRead;No description;165;MGM_LIS3MDL;mission/acs/RwHandler.h 0x4c00;SPPA_NoPacketFound;No description;0;SPACE_PACKET_PARSER;fsfw/src/fsfw/tmtcservices/SpacePacketParser.h 0x4c01;SPPA_SplitPacket;No description;1;SPACE_PACKET_PARSER;fsfw/src/fsfw/tmtcservices/SpacePacketParser.h 0x4fa1;HEATER_CommandNotSupported;No description;161;HEATER_HANDLER;mission/tcs/HeaterHandler.h @@ -480,8 +474,12 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x53b6;STRH_StartrackerAlreadyBooted;Star tracker is already in firmware mode;182;STR_HANDLER;mission/acs/str/StarTrackerHandler.h 0x53b7;STRH_StartrackerNotRunningFirmware;Star tracker must be in firmware mode to run this command;183;STR_HANDLER;mission/acs/str/StarTrackerHandler.h 0x53b8;STRH_StartrackerNotRunningBootloader;Star tracker must be in bootloader mode to run this command;184;STR_HANDLER;mission/acs/str/StarTrackerHandler.h -0x58a0;SUSS_ErrorUnlockMutex;No description;160;SUS_HANDLER;mission/acs/archive/LegacySusHandler.h -0x58a1;SUSS_ErrorLockMutex;No description;161;SUS_HANDLER;mission/acs/archive/LegacySusHandler.h +0x58a0;SUSS_InvalidSpeed;Action Message with invalid speed was received. Valid speeds must be in the range of [-65000, 1000] or [1000, 65000];160;SUS_HANDLER;mission/acs/RwHandler.h +0x58a1;SUSS_InvalidRampTime;Action Message with invalid ramp time was received.;161;SUS_HANDLER;mission/acs/RwHandler.h +0x58a2;SUSS_SetSpeedCommandInvalidLength;Received set speed command has invalid length. Should be 6.;162;SUS_HANDLER;mission/acs/RwHandler.h +0x58a3;SUSS_ExecutionFailed;Command execution failed;163;SUS_HANDLER;mission/acs/RwHandler.h +0x58a4;SUSS_CrcError;Reaction wheel reply has invalid crc;164;SUS_HANDLER;mission/acs/RwHandler.h +0x58a5;SUSS_ValueNotRead;No description;165;SUS_HANDLER;mission/acs/RwHandler.h 0x5d00;GOMS_PacketTooLong;No description;0;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h 0x5d01;GOMS_InvalidTableId;No description;1;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h 0x5d02;GOMS_InvalidAddress;No description;2;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h diff --git a/generators/bsp_q7s_events.csv b/generators/bsp_q7s_events.csv index 086cadc3..d7265738 100644 --- a/generators/bsp_q7s_events.csv +++ b/generators/bsp_q7s_events.csv @@ -203,6 +203,7 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 12801;0x3201;NOT_ENOUGH_DEVICES_DUAL_MODE;HIGH;No description;mission/system/acs/AcsBoardAssembly.h 12802;0x3202;POWER_STATE_MACHINE_TIMEOUT;MEDIUM;No description;mission/system/acs/AcsBoardAssembly.h 12803;0x3203;SIDE_SWITCH_TRANSITION_NOT_ALLOWED;LOW;Not implemented, would increase already high complexity. Operator should instead command the assembly off first and then command the assembly on into the desired mode/submode combination;mission/system/acs/AcsBoardAssembly.h +12804;0x3204;DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY;MEDIUM;This is triggered when the assembly would have normally switched the board side, but the GPS device of the other side was marked faulty. P1: Current submode.;mission/system/acs/AcsBoardAssembly.h 12900;0x3264;TRANSITION_OTHER_SIDE_FAILED;HIGH;No description;mission/system/acs/SusAssembly.h 12901;0x3265;NOT_ENOUGH_DEVICES_DUAL_MODE;HIGH;No description;mission/system/acs/SusAssembly.h 12902;0x3266;POWER_STATE_MACHINE_TIMEOUT;MEDIUM;No description;mission/system/acs/SusAssembly.h @@ -266,14 +267,19 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path 14104;0x3718;OBC_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h 14105;0x3719;CAMERA_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h 14106;0x371a;PCDU_SYSTEM_OVERHEATING;HIGH;No description;mission/controller/tcsDefs.h +14107;0x371b;HEATER_NOT_OFF_FOR_OFF_MODE;MEDIUM;No description;mission/controller/tcsDefs.h 14201;0x3779;TX_TIMER_EXPIRED;INFO;The transmit timer to protect the Syrlinks expired P1: The current timer value;mission/system/com/ComSubsystem.h 14202;0x377a;BIT_LOCK_TX_ON;INFO;Transmitter will be turned on due to detection of bitlock;mission/system/com/ComSubsystem.h 14300;0x37dc;POSSIBLE_FILE_CORRUPTION;LOW;P1: Result code of TM packet parser. P2: Timestamp of possibly corrupt file as a unix timestamp.;mission/persistentTmStoreDefs.h 14301;0x37dd;FILE_TOO_LARGE;LOW;File in store too large. P1: Detected file size P2: Allowed file size;mission/persistentTmStoreDefs.h 14302;0x37de;BUSY_DUMPING_EVENT;INFO;No description;mission/persistentTmStoreDefs.h -14303;0x37df;DUMP_WAS_CANCELLED;LOW;Dump was cancelled. P1: Object ID of store.;mission/persistentTmStoreDefs.h 14305;0x37e1;DUMP_OK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14306;0x37e2;DUMP_NOK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14307;0x37e3;DUMP_MISC_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14308;0x37e4;DUMP_HK_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h 14309;0x37e5;DUMP_CFDP_STORE_DONE;INFO;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14310;0x37e6;DUMP_OK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14311;0x37e7;DUMP_NOK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14312;0x37e8;DUMP_MISC_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14313;0x37e9;DUMP_HK_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h +14314;0x37ea;DUMP_CFDP_CANCELLED;LOW;P1: Number of dumped packets. P2: Total dumped bytes.;mission/persistentTmStoreDefs.h diff --git a/generators/bsp_q7s_objects.csv b/generators/bsp_q7s_objects.csv index 68be8ef2..eedafc52 100644 --- a/generators/bsp_q7s_objects.csv +++ b/generators/bsp_q7s_objects.csv @@ -29,6 +29,8 @@ 0x44120350;RW4 0x44130001;STAR_TRACKER 0x44130045;GPS_CONTROLLER +0x44130046;GPS_0_HEALTH_DEV +0x44130047;GPS_1_HEALTH_DEV 0x44140013;IMTQ_POLLING 0x44140014;IMTQ_HANDLER 0x442000A1;PCDU_HANDLER diff --git a/generators/bsp_q7s_returnvalues.csv b/generators/bsp_q7s_returnvalues.csv index d91b080f..9f6f0379 100644 --- a/generators/bsp_q7s_returnvalues.csv +++ b/generators/bsp_q7s_returnvalues.csv @@ -291,8 +291,8 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x2e02;HPA_InvalidDomainId;No description;2;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h 0x2e03;HPA_InvalidValue;No description;3;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h 0x2e05;HPA_ReadOnly;No description;5;HAS_PARAMETERS_IF;fsfw/src/fsfw/parameters/HasParametersIF.h -0x2f01;ASC_NoPacketFound;No description;1;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/DleParser.h -0x2f02;ASC_PossiblePacketLoss;No description;2;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/DleParser.h +0x2f01;ASC_TooLongForTargetType;No description;1;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h +0x2f02;ASC_InvalidCharacters;No description;2;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h 0x2f03;ASC_BufferTooSmall;No description;3;ASCII_CONVERTER;fsfw/src/fsfw/globalfunctions/AsciiConverter.h 0x3001;POS_InPowerTransition;No description;1;POWER_SWITCHER;fsfw/src/fsfw/power/PowerSwitcher.h 0x3002;POS_SwitchStateMismatch;No description;2;POWER_SWITCHER;fsfw/src/fsfw/power/PowerSwitcher.h @@ -371,8 +371,8 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x3e03;HKM_PeriodicHelperInvalid;No description;3;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h 0x3e04;HKM_PoolobjectNotFound;No description;4;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h 0x3e05;HKM_DatasetNotFound;No description;5;HOUSEKEEPING_MANAGER;fsfw/src/fsfw/datapoollocal/LocalDataPoolManager.h -0x3f01;DLEE_StreamTooShort;No description;1;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h -0x3f02;DLEE_DecodingError;No description;2;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleEncoder.h +0x3f01;DLEE_NoPacketFound;No description;1;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleParser.h +0x3f02;DLEE_PossiblePacketLoss;No description;2;DLE_ENCODER;fsfw/src/fsfw/globalfunctions/DleParser.h 0x4201;PUS11_InvalidTypeTimeWindow;No description;1;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h 0x4202;PUS11_InvalidTimeWindow;No description;2;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h 0x4203;PUS11_TimeshiftingNotPossible;No description;3;PUS_SERVICE_11;fsfw/src/fsfw/pus/Service11TelecommandScheduling.h @@ -402,9 +402,9 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x4403;UXOS_CommandError;Command execution failed;3;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h 0x4404;UXOS_NoCommandLoadedOrPending;;4;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h 0x4406;UXOS_PcloseCallError;No description;6;LINUX_OSAL;fsfw/src/fsfw_hal/linux/CommandExecutor.h -0x4500;HSPI_HalTimeoutRetval;No description;0;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h -0x4501;HSPI_HalBusyRetval;No description;1;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h -0x4502;HSPI_HalErrorRetval;No description;2;HAL_SPI;fsfw/src/fsfw_hal/stm32h7/spi/spiDefinitions.h +0x4500;HSPI_OpeningFileFailed;No description;0;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h +0x4501;HSPI_FullDuplexTransferFailed;No description;1;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h +0x4502;HSPI_HalfDuplexTransferFailed;No description;2;HAL_SPI;fsfw/src/fsfw_hal/linux/spi/SpiComIF.h 0x4601;HURT_UartReadFailure;No description;1;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h 0x4602;HURT_UartReadSizeMissmatch;No description;2;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h 0x4603;HURT_UartRxBufferTooSmall;No description;3;HAL_UART;fsfw/src/fsfw_hal/linux/serial/SerialComIF.h @@ -415,12 +415,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x4805;HGIO_GpioDuplicateDetected;No description;5;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h 0x4806;HGIO_GpioInitFailed;No description;6;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h 0x4807;HGIO_GpioGetValueFailed;No description;7;HAL_GPIO;fsfw/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h -0x4aa0;MGMLIS3_InvalidSpeed;Action Message with invalid speed was received. Valid speeds must be in the range of [-65000, 1000] or [1000, 65000];160;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa1;MGMLIS3_InvalidRampTime;Action Message with invalid ramp time was received.;161;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa2;MGMLIS3_SetSpeedCommandInvalidLength;Received set speed command has invalid length. Should be 6.;162;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa3;MGMLIS3_ExecutionFailed;Command execution failed;163;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa4;MGMLIS3_CrcError;Reaction wheel reply has invalid crc;164;MGM_LIS3MDL;mission/acs/RwHandler.h -0x4aa5;MGMLIS3_ValueNotRead;No description;165;MGM_LIS3MDL;mission/acs/RwHandler.h 0x4c00;SPPA_NoPacketFound;No description;0;SPACE_PACKET_PARSER;fsfw/src/fsfw/tmtcservices/SpacePacketParser.h 0x4c01;SPPA_SplitPacket;No description;1;SPACE_PACKET_PARSER;fsfw/src/fsfw/tmtcservices/SpacePacketParser.h 0x4fa1;HEATER_CommandNotSupported;No description;161;HEATER_HANDLER;mission/tcs/HeaterHandler.h @@ -492,12 +486,16 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x57a1;PLSPVhLP_ProcessTerminated;Process has been terminated by command;161;PLOC_SUPV_HELPER;linux/payload/PlocSupvUartMan.h 0x57a2;PLSPVhLP_PathNotExists;Received command with invalid pathname;162;PLOC_SUPV_HELPER;linux/payload/PlocSupvUartMan.h 0x57a3;PLSPVhLP_EventBufferReplyInvalidApid;Expected event buffer TM but received space packet with other APID;163;PLOC_SUPV_HELPER;linux/payload/PlocSupvUartMan.h -0x58a0;SUSS_ErrorUnlockMutex;No description;160;SUS_HANDLER;mission/acs/archive/LegacySusHandler.h -0x58a1;SUSS_ErrorLockMutex;No description;161;SUS_HANDLER;mission/acs/archive/LegacySusHandler.h +0x58a0;SUSS_InvalidSpeed;Action Message with invalid speed was received. Valid speeds must be in the range of [-65000, 1000] or [1000, 65000];160;SUS_HANDLER;mission/acs/RwHandler.h +0x58a1;SUSS_InvalidRampTime;Action Message with invalid ramp time was received.;161;SUS_HANDLER;mission/acs/RwHandler.h +0x58a2;SUSS_SetSpeedCommandInvalidLength;Received set speed command has invalid length. Should be 6.;162;SUS_HANDLER;mission/acs/RwHandler.h +0x58a3;SUSS_ExecutionFailed;Command execution failed;163;SUS_HANDLER;mission/acs/RwHandler.h +0x58a4;SUSS_CrcError;Reaction wheel reply has invalid crc;164;SUS_HANDLER;mission/acs/RwHandler.h +0x58a5;SUSS_ValueNotRead;No description;165;SUS_HANDLER;mission/acs/RwHandler.h +0x5900;IPCI_NoReplyAvailable;No description;0;CCSDS_IP_CORE_BRIDGE;linux/acs/ImtqPollingTask.h 0x5901;IPCI_NoPacketFound;No description;1;CCSDS_IP_CORE_BRIDGE;linux/com/SyrlinksComHandler.h 0x59a0;IPCI_PapbBusy;No description;160;CCSDS_IP_CORE_BRIDGE;linux/ipcore/PapbVcInterface.h 0x5aa0;PTME_UnknownVcId;No description;160;PTME;linux/ipcore/Ptme.h -0x5c00;STRHLP_NoReplyAvailable;No description;0;STR_HELPER;linux/acs/ImtqPollingTask.h 0x5c01;STRHLP_SdNotMounted;SD card specified in path string not mounted;1;STR_HELPER;linux/acs/StrComHandler.h 0x5c02;STRHLP_FileNotExists;Specified file does not exist on filesystem;2;STR_HELPER;linux/acs/StrComHandler.h 0x5c03;STRHLP_PathNotExists;Specified path does not exist;3;STR_HELPER;linux/acs/StrComHandler.h @@ -515,7 +513,6 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x5d03;GOMS_InvalidParamSize;No description;3;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h 0x5d04;GOMS_InvalidPayloadSize;No description;4;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h 0x5d05;GOMS_UnknownReplyId;No description;5;GOM_SPACE_HANDLER;mission/power/GomspaceDeviceHandler.h -0x5e02;PLMEMDUMP_InvalidCrc;No description;2;PLOC_MEMORY_DUMPER;linux/payload/ScexHelper.h 0x5ea0;PLMEMDUMP_MramAddressTooHigh;The capacity of the MRAM amounts to 512 kB. Thus the maximum address must not be higher than 0x7d000.;160;PLOC_MEMORY_DUMPER;linux/payload/PlocMemoryDumper.h 0x5ea1;PLMEMDUMP_MramInvalidAddressCombination;The specified end address is lower than the start address;161;PLOC_MEMORY_DUMPER;linux/payload/PlocMemoryDumper.h 0x5fa0;PDEC_AbandonedCltuRetval;No description;160;PDEC_HANDLER;linux/ipcore/PdecHandler.h @@ -544,6 +541,7 @@ Full ID (hex); Name; Description; Unique ID; Subsytem Name; File Path 0x63a0;NVMB_KeyNotExists;Specified key does not exist in json file;160;NVM_PARAM_BASE;mission/memory/NvmParameterBase.h 0x64a0;FSHLP_SdNotMounted;SD card specified with path string not mounted;160;FILE_SYSTEM_HELPER;bsp_q7s/fs/FilesystemHelper.h 0x64a1;FSHLP_FileNotExists;Specified file does not exist on filesystem;161;FILE_SYSTEM_HELPER;bsp_q7s/fs/FilesystemHelper.h +0x6502;PLMPHLP_InvalidCrc;No description;2;PLOC_MPSOC_HELPER;linux/payload/ScexHelper.h 0x65a0;PLMPHLP_FileClosedAccidentally;File accidentally close;160;PLOC_MPSOC_HELPER;linux/payload/PlocMpsocHelper.h 0x66a0;SADPL_CommandNotSupported;No description;160;SA_DEPL_HANDLER;mission/SolarArrayDeploymentHandler.h 0x66a1;SADPL_DeploymentAlreadyExecuting;No description;161;SA_DEPL_HANDLER;mission/SolarArrayDeploymentHandler.h diff --git a/generators/events/translateEvents.cpp b/generators/events/translateEvents.cpp index e29ee7ce..8bce9e73 100644 --- a/generators/events/translateEvents.cpp +++ b/generators/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 278 translations. + * @brief Auto-generated event translation file. Contains 284 translations. * @details - * Generated on: 2023-03-26 16:47:32 + * Generated on: 2023-03-31 19:17:49 */ #include "translateEvents.h" @@ -209,6 +209,7 @@ const char *TRANSITION_OTHER_SIDE_FAILED_STRING = "TRANSITION_OTHER_SIDE_FAILED" const char *NOT_ENOUGH_DEVICES_DUAL_MODE_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE"; const char *POWER_STATE_MACHINE_TIMEOUT_STRING = "POWER_STATE_MACHINE_TIMEOUT"; const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING = "SIDE_SWITCH_TRANSITION_NOT_ALLOWED"; +const char *DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING = "DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY"; const char *TRANSITION_OTHER_SIDE_FAILED_12900_STRING = "TRANSITION_OTHER_SIDE_FAILED_12900"; const char *NOT_ENOUGH_DEVICES_DUAL_MODE_12901_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE_12901"; const char *POWER_STATE_MACHINE_TIMEOUT_12902_STRING = "POWER_STATE_MACHINE_TIMEOUT_12902"; @@ -272,17 +273,22 @@ const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING"; const char *OBC_OVERHEATING_STRING = "OBC_OVERHEATING"; const char *CAMERA_OVERHEATING_STRING = "CAMERA_OVERHEATING"; const char *PCDU_SYSTEM_OVERHEATING_STRING = "PCDU_SYSTEM_OVERHEATING"; +const char *HEATER_NOT_OFF_FOR_OFF_MODE_STRING = "HEATER_NOT_OFF_FOR_OFF_MODE"; const char *TX_TIMER_EXPIRED_STRING = "TX_TIMER_EXPIRED"; const char *BIT_LOCK_TX_ON_STRING = "BIT_LOCK_TX_ON"; const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION"; const char *FILE_TOO_LARGE_STRING = "FILE_TOO_LARGE"; const char *BUSY_DUMPING_EVENT_STRING = "BUSY_DUMPING_EVENT"; -const char *DUMP_WAS_CANCELLED_STRING = "DUMP_WAS_CANCELLED"; const char *DUMP_OK_STORE_DONE_STRING = "DUMP_OK_STORE_DONE"; const char *DUMP_NOK_STORE_DONE_STRING = "DUMP_NOK_STORE_DONE"; const char *DUMP_MISC_STORE_DONE_STRING = "DUMP_MISC_STORE_DONE"; const char *DUMP_HK_STORE_DONE_STRING = "DUMP_HK_STORE_DONE"; const char *DUMP_CFDP_STORE_DONE_STRING = "DUMP_CFDP_STORE_DONE"; +const char *DUMP_OK_CANCELLED_STRING = "DUMP_OK_CANCELLED"; +const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED"; +const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED"; +const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED"; +const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED"; const char *translateEvents(Event event) { switch ((event & 0xFFFF)) { @@ -694,6 +700,8 @@ const char *translateEvents(Event event) { return POWER_STATE_MACHINE_TIMEOUT_STRING; case (12803): return SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING; + case (12804): + return DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING; case (12900): return TRANSITION_OTHER_SIDE_FAILED_12900_STRING; case (12901): @@ -820,6 +828,8 @@ const char *translateEvents(Event event) { return CAMERA_OVERHEATING_STRING; case (14106): return PCDU_SYSTEM_OVERHEATING_STRING; + case (14107): + return HEATER_NOT_OFF_FOR_OFF_MODE_STRING; case (14201): return TX_TIMER_EXPIRED_STRING; case (14202): @@ -830,8 +840,6 @@ const char *translateEvents(Event event) { return FILE_TOO_LARGE_STRING; case (14302): return BUSY_DUMPING_EVENT_STRING; - case (14303): - return DUMP_WAS_CANCELLED_STRING; case (14305): return DUMP_OK_STORE_DONE_STRING; case (14306): @@ -842,6 +850,16 @@ const char *translateEvents(Event event) { return DUMP_HK_STORE_DONE_STRING; case (14309): return DUMP_CFDP_STORE_DONE_STRING; + case (14310): + return DUMP_OK_CANCELLED_STRING; + case (14311): + return DUMP_NOK_CANCELLED_STRING; + case (14312): + return DUMP_MISC_CANCELLED_STRING; + case (14313): + return DUMP_HK_CANCELLED_STRING; + case (14314): + return DUMP_CFDP_CANCELLED_STRING; default: return "UNKNOWN_EVENT"; } diff --git a/generators/objects/translateObjects.cpp b/generators/objects/translateObjects.cpp index 9027fa8e..f08a8f38 100644 --- a/generators/objects/translateObjects.cpp +++ b/generators/objects/translateObjects.cpp @@ -1,8 +1,8 @@ /** * @brief Auto-generated object translation file. * @details - * Contains 173 translations. - * Generated on: 2023-03-26 16:47:32 + * Contains 175 translations. + * Generated on: 2023-03-31 19:17:49 */ #include "translateObjects.h" @@ -37,6 +37,8 @@ const char *GYRO_3_L3G_HANDLER_STRING = "GYRO_3_L3G_HANDLER"; const char *RW4_STRING = "RW4"; const char *STAR_TRACKER_STRING = "STAR_TRACKER"; const char *GPS_CONTROLLER_STRING = "GPS_CONTROLLER"; +const char *GPS_0_HEALTH_DEV_STRING = "GPS_0_HEALTH_DEV"; +const char *GPS_1_HEALTH_DEV_STRING = "GPS_1_HEALTH_DEV"; const char *IMTQ_POLLING_STRING = "IMTQ_POLLING"; const char *IMTQ_HANDLER_STRING = "IMTQ_HANDLER"; const char *PCDU_HANDLER_STRING = "PCDU_HANDLER"; @@ -244,6 +246,10 @@ const char *translateObject(object_id_t object) { return STAR_TRACKER_STRING; case 0x44130045: return GPS_CONTROLLER_STRING; + case 0x44130046: + return GPS_0_HEALTH_DEV_STRING; + case 0x44130047: + return GPS_1_HEALTH_DEV_STRING; case 0x44140013: return IMTQ_POLLING_STRING; case 0x44140014: diff --git a/linux/acs/GpsHyperionLinuxController.cpp b/linux/acs/GpsHyperionLinuxController.cpp index 0b971f49..b5dc8a1f 100644 --- a/linux/acs/GpsHyperionLinuxController.cpp +++ b/linux/acs/GpsHyperionLinuxController.cpp @@ -99,6 +99,7 @@ void GpsHyperionLinuxController::setResetPinTriggerFunction(gpioResetFunction_t ReturnValue_t GpsHyperionLinuxController::performOperation(uint8_t opCode) { handleQueue(); poolManager.performHkOperation(); + while (true) { #if OBSW_THREAD_TRACING == 1 trace::threadTrace(opCounter, "GPS CTRL"); diff --git a/linux/fsfwconfig/events/translateEvents.cpp b/linux/fsfwconfig/events/translateEvents.cpp index 38224ad6..8bce9e73 100644 --- a/linux/fsfwconfig/events/translateEvents.cpp +++ b/linux/fsfwconfig/events/translateEvents.cpp @@ -1,7 +1,7 @@ /** - * @brief Auto-generated event translation file. Contains 278 translations. + * @brief Auto-generated event translation file. Contains 284 translations. * @details - * Generated on: 2023-03-26 16:47:32 + * Generated on: 2023-03-31 19:17:49 */ #include "translateEvents.h" @@ -209,11 +209,11 @@ const char *TRANSITION_OTHER_SIDE_FAILED_STRING = "TRANSITION_OTHER_SIDE_FAILED" const char *NOT_ENOUGH_DEVICES_DUAL_MODE_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE"; const char *POWER_STATE_MACHINE_TIMEOUT_STRING = "POWER_STATE_MACHINE_TIMEOUT"; const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING = "SIDE_SWITCH_TRANSITION_NOT_ALLOWED"; +const char *DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING = "DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY"; const char *TRANSITION_OTHER_SIDE_FAILED_12900_STRING = "TRANSITION_OTHER_SIDE_FAILED_12900"; const char *NOT_ENOUGH_DEVICES_DUAL_MODE_12901_STRING = "NOT_ENOUGH_DEVICES_DUAL_MODE_12901"; const char *POWER_STATE_MACHINE_TIMEOUT_12902_STRING = "POWER_STATE_MACHINE_TIMEOUT_12902"; -const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903_STRING = - "SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903"; +const char *SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903_STRING = "SIDE_SWITCH_TRANSITION_NOT_ALLOWED_12903"; const char *CHILDREN_LOST_MODE_STRING = "CHILDREN_LOST_MODE"; const char *GPS_FIX_CHANGE_STRING = "GPS_FIX_CHANGE"; const char *CANT_GET_FIX_STRING = "CANT_GET_FIX"; @@ -273,17 +273,22 @@ const char *SYRLINKS_OVERHEATING_STRING = "SYRLINKS_OVERHEATING"; const char *OBC_OVERHEATING_STRING = "OBC_OVERHEATING"; const char *CAMERA_OVERHEATING_STRING = "CAMERA_OVERHEATING"; const char *PCDU_SYSTEM_OVERHEATING_STRING = "PCDU_SYSTEM_OVERHEATING"; +const char *HEATER_NOT_OFF_FOR_OFF_MODE_STRING = "HEATER_NOT_OFF_FOR_OFF_MODE"; const char *TX_TIMER_EXPIRED_STRING = "TX_TIMER_EXPIRED"; const char *BIT_LOCK_TX_ON_STRING = "BIT_LOCK_TX_ON"; const char *POSSIBLE_FILE_CORRUPTION_STRING = "POSSIBLE_FILE_CORRUPTION"; const char *FILE_TOO_LARGE_STRING = "FILE_TOO_LARGE"; const char *BUSY_DUMPING_EVENT_STRING = "BUSY_DUMPING_EVENT"; -const char *DUMP_WAS_CANCELLED_STRING = "DUMP_WAS_CANCELLED"; const char *DUMP_OK_STORE_DONE_STRING = "DUMP_OK_STORE_DONE"; const char *DUMP_NOK_STORE_DONE_STRING = "DUMP_NOK_STORE_DONE"; const char *DUMP_MISC_STORE_DONE_STRING = "DUMP_MISC_STORE_DONE"; const char *DUMP_HK_STORE_DONE_STRING = "DUMP_HK_STORE_DONE"; const char *DUMP_CFDP_STORE_DONE_STRING = "DUMP_CFDP_STORE_DONE"; +const char *DUMP_OK_CANCELLED_STRING = "DUMP_OK_CANCELLED"; +const char *DUMP_NOK_CANCELLED_STRING = "DUMP_NOK_CANCELLED"; +const char *DUMP_MISC_CANCELLED_STRING = "DUMP_MISC_CANCELLED"; +const char *DUMP_HK_CANCELLED_STRING = "DUMP_HK_CANCELLED"; +const char *DUMP_CFDP_CANCELLED_STRING = "DUMP_CFDP_CANCELLED"; const char *translateEvents(Event event) { switch ((event & 0xFFFF)) { @@ -695,6 +700,8 @@ const char *translateEvents(Event event) { return POWER_STATE_MACHINE_TIMEOUT_STRING; case (12803): return SIDE_SWITCH_TRANSITION_NOT_ALLOWED_STRING; + case (12804): + return DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY_STRING; case (12900): return TRANSITION_OTHER_SIDE_FAILED_12900_STRING; case (12901): @@ -821,6 +828,8 @@ const char *translateEvents(Event event) { return CAMERA_OVERHEATING_STRING; case (14106): return PCDU_SYSTEM_OVERHEATING_STRING; + case (14107): + return HEATER_NOT_OFF_FOR_OFF_MODE_STRING; case (14201): return TX_TIMER_EXPIRED_STRING; case (14202): @@ -831,8 +840,6 @@ const char *translateEvents(Event event) { return FILE_TOO_LARGE_STRING; case (14302): return BUSY_DUMPING_EVENT_STRING; - case (14303): - return DUMP_WAS_CANCELLED_STRING; case (14305): return DUMP_OK_STORE_DONE_STRING; case (14306): @@ -843,6 +850,16 @@ const char *translateEvents(Event event) { return DUMP_HK_STORE_DONE_STRING; case (14309): return DUMP_CFDP_STORE_DONE_STRING; + case (14310): + return DUMP_OK_CANCELLED_STRING; + case (14311): + return DUMP_NOK_CANCELLED_STRING; + case (14312): + return DUMP_MISC_CANCELLED_STRING; + case (14313): + return DUMP_HK_CANCELLED_STRING; + case (14314): + return DUMP_CFDP_CANCELLED_STRING; default: return "UNKNOWN_EVENT"; } diff --git a/linux/fsfwconfig/objects/translateObjects.cpp b/linux/fsfwconfig/objects/translateObjects.cpp index 9027fa8e..f08a8f38 100644 --- a/linux/fsfwconfig/objects/translateObjects.cpp +++ b/linux/fsfwconfig/objects/translateObjects.cpp @@ -1,8 +1,8 @@ /** * @brief Auto-generated object translation file. * @details - * Contains 173 translations. - * Generated on: 2023-03-26 16:47:32 + * Contains 175 translations. + * Generated on: 2023-03-31 19:17:49 */ #include "translateObjects.h" @@ -37,6 +37,8 @@ const char *GYRO_3_L3G_HANDLER_STRING = "GYRO_3_L3G_HANDLER"; const char *RW4_STRING = "RW4"; const char *STAR_TRACKER_STRING = "STAR_TRACKER"; const char *GPS_CONTROLLER_STRING = "GPS_CONTROLLER"; +const char *GPS_0_HEALTH_DEV_STRING = "GPS_0_HEALTH_DEV"; +const char *GPS_1_HEALTH_DEV_STRING = "GPS_1_HEALTH_DEV"; const char *IMTQ_POLLING_STRING = "IMTQ_POLLING"; const char *IMTQ_HANDLER_STRING = "IMTQ_HANDLER"; const char *PCDU_HANDLER_STRING = "PCDU_HANDLER"; @@ -244,6 +246,10 @@ const char *translateObject(object_id_t object) { return STAR_TRACKER_STRING; case 0x44130045: return GPS_CONTROLLER_STRING; + case 0x44130046: + return GPS_0_HEALTH_DEV_STRING; + case 0x44130047: + return GPS_1_HEALTH_DEV_STRING; case 0x44140013: return IMTQ_POLLING_STRING; case 0x44140014: diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp index 8c98df90..60968cc6 100644 --- a/linux/ipcore/PapbVcInterface.cpp +++ b/linux/ipcore/PapbVcInterface.cpp @@ -2,6 +2,9 @@ #include #include +#include +#include + #include "fsfw/serviceinterface/ServiceInterface.h" PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, @@ -16,30 +19,71 @@ PapbVcInterface::~PapbVcInterface() {} ReturnValue_t PapbVcInterface::initialize() { UioMapper uioMapper(uioFile, mapNum); - uint32_t* baseReg; - ReturnValue_t result = uioMapper.getMappedAdress(&baseReg, UioMapper::Permissions::WRITE_ONLY); + ReturnValue_t result = uioMapper.getMappedAdress(const_cast(&vcBaseReg), + UioMapper::Permissions::WRITE_ONLY); if (result != returnvalue::OK) { return result; } - vcBaseReg = baseReg; return returnvalue::OK; } ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { - if (pollPapbBusySignal(0, 0) == returnvalue::OK) { - startPacketTransfer(); + // There are no packets smaller than 4, this is considered a configuration error. + if (size < 4) { + return returnvalue::FAILED; + } + if (pollInterfaceReadiness(0, true) == returnvalue::OK) { + startPacketTransfer(ByteWidthCfg::ONE); } else { return DirectTmSinkIF::IS_BUSY; } + // TODO: This should work but does not.. :( + // size_t idx = 0; + // while (idx < size) { + // + // nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + // if ((size - idx) < 4) { + // *vcBaseReg = CONFIG_DATA_INPUT | (size - idx - 1); + // usleep(1); + // } + // if (pollPapbBusySignal(2) == returnvalue::OK) { + // // vcBaseReg + DATA_REG_OFFSET + 3 = static_cast(data + idx); + // // vcBaseReg + DATA_REG_OFFSET + 2 = static_cast(data + idx + 1); + // // vcBaseReg + DATA_REG_OFFSET + 1 = static_cast(data + idx + 2); + // // vcBaseReg + DATA_REG_OFFSET = static_cast(data + idx + 3); + // + // // std::memcpy((vcBaseReg + DATA_REG_OFFSET), data + idx , nextWriteSize); + // *(vcBaseReg + DATA_REG_OFFSET) = *reinterpret_cast(data + idx); + // //uint8_t* byteReg = reinterpret_cast(vcBaseReg + DATA_REG_OFFSET); + // + // //byteReg[0] = data[idx]; + // //byteReg[1] = data[idx]; + // } else { + // abortPacketTransfer(); + // return returnvalue::FAILED; + // } + // // TODO: Change this after the bugfix. Right now, the PAPB ignores the content of the byte + // // width configuration.5 + // // It's okay to increment by a larger amount for the last segment here, loop will be over + // // in any case. + // idx += 4; + // } for (size_t idx = 0; idx < size; idx++) { - if (pollPapbBusySignal(10, 10) == returnvalue::OK) { + // This delay is super-important, DO NOT REMOVE! + // Polling the GPIO or the config register too often messes up the scheduler. + // TODO: Maybe this should not be done like this. It would be better if there was a custom + // FPGA module which can accept packets and then takes care of dumping that packet into + // the PTME. DMA would be an ideal solution for this. + nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + if (pollInterfaceReadiness(2, false) == returnvalue::OK) { *(vcBaseReg + DATA_REG_OFFSET) = static_cast(data[idx]); } else { abortPacketTransfer(); return returnvalue::FAILED; } } - if (pollPapbBusySignal(10, 10) == returnvalue::OK) { + nanosleep(&BETWEEN_POLL_DELAY, &remDelay); + if (pollInterfaceReadiness(2, false) == returnvalue::OK) { completePacketTransfer(); } else { abortPacketTransfer(); @@ -48,34 +92,41 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) { return returnvalue::OK; } -void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; } +void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) { + *vcBaseReg = CONFIG_DATA_INPUT | initWidth; +} void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; } -ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries, - uint32_t retryDelayUs) const { - gpio::Levels papbBusyState = gpio::Levels::LOW; - ReturnValue_t result; +ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries, + bool checkReadyState) const { uint32_t busyIdx = 0; + nextDelay.tv_nsec = FIRST_DELAY_PAPB_POLLING_NS; while (true) { - /** Check if PAPB interface is ready to receive data */ - result = gpioComIF->readGpio(papbBusyId, papbBusyState); - if (result != returnvalue::OK) { - sif::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal" - << std::endl; - return returnvalue::FAILED; - } - if (papbBusyState == gpio::Levels::HIGH) { + // Check if PAPB interface is ready to receive data. Use the configuration register for this. + // Bit 5, see PTME ptme_001_01-0-7-r2 Table 31. + uint32_t reg = *vcBaseReg; + bool busy = (reg >> 5) & 0b1; + bool ready = (reg >> 6) & 0b1; + if (not busy) { return returnvalue::OK; } + if (checkReadyState and not ready) { + return PAPB_BUSY; + } busyIdx++; if (busyIdx >= maxPollRetries) { return PAPB_BUSY; } - usleep(retryDelayUs); + // Ignore signal handling here for now. + nanosleep(&nextDelay, &remDelay); + // Adaptive delay. + if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) { + nextDelay.tv_nsec *= 2; + } } return returnvalue::OK; } @@ -100,7 +151,7 @@ void PapbVcInterface::isVcInterfaceBufferEmpty() { return; } -bool PapbVcInterface::isBusy() const { return pollPapbBusySignal(0, 0) == PAPB_BUSY; } +bool PapbVcInterface::isBusy() const { return pollInterfaceReadiness(0, true) == PAPB_BUSY; } void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); } diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h index 7491398c..e54def5d 100644 --- a/linux/ipcore/PapbVcInterface.h +++ b/linux/ipcore/PapbVcInterface.h @@ -5,6 +5,8 @@ #include #include +#include + #include "OBSWConfig.h" #include "fsfw/returnvalues/returnvalue.h" @@ -50,13 +52,14 @@ class PapbVcInterface : public VirtualChannelIF { static const ReturnValue_t PAPB_BUSY = MAKE_RETURN_CODE(0xA0); + enum ByteWidthCfg : uint32_t { ONE = 0b00, TWO = 0b01, THREE = 0b10, FOUR = 0b11 }; /** * Configuration bits: * bit[1:0]: Size of data (1,2,3 or 4 bytes). 1 Byte <=> b00 * bit[2]: Set this bit to 1 to abort a transferred packet * bit[3]: Signals to VcInterface the start of a new telemetry packet */ - static constexpr uint32_t CONFIG_START = 0b00001000; + static constexpr uint32_t CONFIG_DATA_INPUT = 0b00001000; /** * Abort a transferred packet. @@ -76,6 +79,9 @@ class PapbVcInterface : public VirtualChannelIF { */ static const int DATA_REG_OFFSET = 256; + static constexpr long int FIRST_DELAY_PAPB_POLLING_NS = 10; + static constexpr long int MAX_DELAY_PAPB_POLLING_NS = 40; + LinuxLibgpioIF* gpioComIF = nullptr; /** Pulled to low when virtual channel not ready to receive data */ @@ -85,6 +91,9 @@ class PapbVcInterface : public VirtualChannelIF { std::string uioFile; int mapNum = 0; + mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0}; + const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10}; + mutable struct timespec remDelay; volatile uint32_t* vcBaseReg = nullptr; @@ -94,7 +103,7 @@ class PapbVcInterface : public VirtualChannelIF { * @brief This function sends the config byte to the virtual channel of the PTME IP Core * to initiate a packet transfer. */ - void startPacketTransfer(); + void startPacketTransfer(ByteWidthCfg initWidth); void abortPacketTransfer(); @@ -111,7 +120,7 @@ class PapbVcInterface : public VirtualChannelIF { * * @return returnvalue::OK when ready to receive data else PAPB_BUSY. */ - ReturnValue_t pollPapbBusySignal(uint32_t maxPollRetries, uint32_t retryDelayUs) const; + inline ReturnValue_t pollInterfaceReadiness(uint32_t maxPollRetries, bool checkReadyState) const; /** * @brief This function can be used for debugging to check whether there are packets in diff --git a/mission/acs/GyrAdis1650XHandler.cpp b/mission/acs/GyrAdis1650XHandler.cpp index 63a28366..57033e80 100644 --- a/mission/acs/GyrAdis1650XHandler.cpp +++ b/mission/acs/GyrAdis1650XHandler.cpp @@ -87,12 +87,11 @@ ReturnValue_t GyrAdis1650XHandler::scanForReply(const uint8_t *start, size_t rem getMode() == _MODE_POWER_DOWN) { return IGNORE_FULL_PACKET; } + *foundLen = remainingSize; if (remainingSize != sizeof(acs::Adis1650XReply)) { - *foundLen = remainingSize; return returnvalue::FAILED; } *foundId = adis1650x::REPLY; - *foundLen = remainingSize; if (internalState == InternalState::SHUTDOWN) { commandExecuted = true; } diff --git a/mission/acs/GyrL3gCustomHandler.cpp b/mission/acs/GyrL3gCustomHandler.cpp index fd576791..934fba99 100644 --- a/mission/acs/GyrL3gCustomHandler.cpp +++ b/mission/acs/GyrL3gCustomHandler.cpp @@ -99,12 +99,11 @@ ReturnValue_t GyrL3gCustomHandler::scanForReply(const uint8_t *start, size_t len if (getMode() == _MODE_WAIT_OFF or getMode() == _MODE_WAIT_ON or getMode() == _MODE_POWER_DOWN) { return IGNORE_FULL_PACKET; } + *foundLen = len; if (len != sizeof(acs::GyroL3gReply)) { - *foundLen = len; return returnvalue::FAILED; } - *foundId = l3gd20h::REPLY; - *foundLen = len; + *foundId = adis1650x::REPLY; if (internalState == InternalState::SHUTDOWN) { commandExecuted = true; } diff --git a/mission/com/CMakeLists.txt b/mission/com/CMakeLists.txt index 94d3e7f0..90e90c88 100644 --- a/mission/com/CMakeLists.txt +++ b/mission/com/CMakeLists.txt @@ -1,2 +1,11 @@ -target_sources(${LIB_EIVE_MISSION} PRIVATE SyrlinksHandler.cpp - CcsdsIpCoreHandler.cpp) +target_sources( + ${LIB_EIVE_MISSION} + PRIVATE SyrlinksHandler.cpp + CcsdsIpCoreHandler.cpp + LiveTmTask.cpp + PersistentLogTmStoreTask.cpp + TmStoreTaskBase.cpp + VirtualChannel.cpp + VirtualChannelWithQueue.cpp + PersistentSingleTmStoreTask.cpp + LiveTmTask.cpp) diff --git a/mission/com/CcsdsIpCoreHandler.cpp b/mission/com/CcsdsIpCoreHandler.cpp index 806096b8..d260d50e 100644 --- a/mission/com/CcsdsIpCoreHandler.cpp +++ b/mission/com/CcsdsIpCoreHandler.cpp @@ -15,9 +15,11 @@ CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig, std::atomic_bool& linkState, - GpioIF* gpioIF, PtmeGpios gpioIds) + GpioIF* gpioIF, PtmeGpios gpioIds, + std::atomic_bool& ptmeLocked) : SystemObject(objectId), linkState(linkState), + ptmeLocked(ptmeLocked), tcDestination(tcDestination), parameterHelper(this), actionHelper(this, nullptr), @@ -29,12 +31,14 @@ CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDesti auto mqArgs = MqArgs(objectId, static_cast(this)); eventQueue = QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs); + ptmeLocked = true; } CcsdsIpCoreHandler::~CcsdsIpCoreHandler() = default; ReturnValue_t CcsdsIpCoreHandler::performOperation(uint8_t operationCode) { readCommandQueue(); + performPtmeUpdateWhenApplicable(); return returnvalue::OK; } @@ -76,6 +80,8 @@ ReturnValue_t CcsdsIpCoreHandler::initialize() { } else { enablePrioritySelectMode(); } + resetPtme(); + ptmeLocked = false; #if OBSW_SYRLINKS_SIMULATED == 1 // Update data on rising edge @@ -127,10 +133,15 @@ ReturnValue_t CcsdsIpCoreHandler::getParameter(uint8_t domainId, uint8_t uniqueI return HasParametersIF::INVALID_VALUE; } parameterWrapper->set(batPriorityParam); - if (mode == MODE_ON) { - updateBatPriorityOnTxOff = true; - } else if (mode == MODE_OFF) { - updateBatPriorityFromParam(); + if (newVal != batPriorityParam) { + // This ensures that the BAT priority is updated at some point when an update of the PTME is + // allowed + updateContext.updateBatPrio = true; + // If we are off, we can do the update after X cycles. Otherwise, wait until the transmitter + // goes off. + if (mode == MODE_OFF) { + initPtmeUpdateAfterXCycles(); + } } return returnvalue::OK; } @@ -148,36 +159,12 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu const uint8_t* data, size_t size) { ReturnValue_t result = returnvalue::OK; switch (actionId) { - case SET_LOW_RATE: { - submode = static_cast(com::CcsdsSubmode::DATARATE_LOW); - result = ptmeConfig.setRate(RATE_100KBPS); - break; - } - case SET_HIGH_RATE: { - submode = static_cast(com::CcsdsSubmode::DATARATE_HIGH); - result = ptmeConfig.setRate(RATE_500KBPS); - break; - } case ARBITRARY_RATE: { uint32_t bitrate = 0; SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG); result = ptmeConfig.setRate(bitrate); break; } - case EN_TRANSMITTER: { - enableTransmit(); - if (mode == HasModesIF::MODE_OFF) { - mode = HasModesIF::MODE_ON; - } - return EXECUTION_FINISHED; - } - case DISABLE_TRANSMITTER: { - disableTransmit(); - if (mode == HasModesIF::MODE_ON) { - mode = HasModesIF::MODE_OFF; - } - return EXECUTION_FINISHED; - } case ENABLE_TX_CLK_MANIPULATOR: { result = ptmeConfig.configTxManipulator(true); break; @@ -206,12 +193,8 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu void CcsdsIpCoreHandler::updateLinkState() { linkState = LINK_UP; } void CcsdsIpCoreHandler::enableTransmit() { - // Reset PTME on each transmit enable. - updateBatPriorityFromParam(); -#ifndef TE0720_1CFA gpioIF->pullHigh(ptmeGpios.enableTxClock); gpioIF->pullHigh(ptmeGpios.enableTxData); -#endif linkState = LINK_UP; } @@ -236,34 +219,23 @@ ReturnValue_t CcsdsIpCoreHandler::checkModeCommand(Mode_t mode, Submode_t submod } void CcsdsIpCoreHandler::startTransition(Mode_t mode, Submode_t submode) { - auto rateSet = [&](uint32_t rate) { - ReturnValue_t result = ptmeConfig.setRate(rate); - if (result == returnvalue::OK) { - this->mode = HasModesIF::MODE_ON; - } - }; + triggerEvent(CHANGING_MODE, mode, submode); if (mode == HasModesIF::MODE_ON) { - enableTransmit(); - if (submode == static_cast(com::CcsdsSubmode::DATARATE_DEFAULT)) { - com::Datarate currentDatarate = com::getCurrentDatarate(); - if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) { - rateSet(RATE_100KBPS); - } else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) { - rateSet(RATE_500KBPS); - } - } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_HIGH)) { - rateSet(RATE_500KBPS); - } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_LOW)) { - rateSet(RATE_100KBPS); + if (this->submode != submode) { + initPtmeUpdateAfterXCycles(); + updateContext.enableTransmitAfterPtmeUpdate = true; + updateContext.updateClockRate = true; + this->submode = submode; + this->mode = mode; + updateContext.setModeAfterUpdate = true; + return; } - + // No rate change, so enable transmitter right away. + enableTransmit(); } else if (mode == HasModesIF::MODE_OFF) { disableTransmit(); - this->mode = HasModesIF::MODE_OFF; } - this->submode = submode; - modeHelper.modeChanged(mode, submode); - announceMode(false); + setMode(mode, submode); } void CcsdsIpCoreHandler::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); } @@ -274,9 +246,9 @@ void CcsdsIpCoreHandler::disableTransmit() { gpioIF->pullLow(ptmeGpios.enableTxData); #endif linkState = LINK_DOWN; - if (updateBatPriorityOnTxOff) { - updateBatPriorityFromParam(); - updateBatPriorityOnTxOff = false; + // Some parameters need update and transmitter is off now. + if (updateContext.updateBatPrio or updateContext.updateClockRate) { + initPtmeUpdateAfterXCycles(); } } @@ -294,21 +266,9 @@ ModeTreeChildIF& CcsdsIpCoreHandler::getModeTreeChildIF() { return *this; } object_id_t CcsdsIpCoreHandler::getObjectId() const { return SystemObject::getObjectId(); } -void CcsdsIpCoreHandler::enablePrioritySelectMode() { - ptmeConfig.enableBatPriorityBit(true); - // Reset the PTME - gpioIF->pullLow(ptmeGpios.ptmeResetn); - usleep(10); - gpioIF->pullHigh(ptmeGpios.ptmeResetn); -} +void CcsdsIpCoreHandler::enablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(true); } -void CcsdsIpCoreHandler::disablePrioritySelectMode() { - ptmeConfig.enableBatPriorityBit(false); - // Reset the PTME - gpioIF->pullLow(ptmeGpios.ptmeResetn); - usleep(10); - gpioIF->pullHigh(ptmeGpios.ptmeResetn); -} +void CcsdsIpCoreHandler::disablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(false); } void CcsdsIpCoreHandler::updateBatPriorityFromParam() { if (batPriorityParam == 0) { @@ -317,3 +277,79 @@ void CcsdsIpCoreHandler::updateBatPriorityFromParam() { enablePrioritySelectMode(); } } + +void CcsdsIpCoreHandler::setMode(Mode_t mode, Submode_t submode) { + this->submode = submode; + this->mode = mode; + modeHelper.modeChanged(mode, submode); + announceMode(false); +} + +void CcsdsIpCoreHandler::performPtmeUpdateWhenApplicable() { + if (not updateContext.performPtmeUpdateAfterXCycles) { + return; + } + if (updateContext.ptmeUpdateCycleCount >= 2) { + if (updateContext.updateBatPrio) { + updateBatPriorityFromParam(); + updateContext.updateBatPrio = false; + } + ReturnValue_t result = returnvalue::OK; + if (updateContext.updateClockRate) { + if (submode == static_cast(com::CcsdsSubmode::DATARATE_DEFAULT)) { + com::Datarate currentDatarate = com::getCurrentDatarate(); + if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) { + result = ptmeConfig.setRate(RATE_100KBPS); + } else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) { + result = ptmeConfig.setRate(RATE_500KBPS); + } + } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_HIGH)) { + result = ptmeConfig.setRate(RATE_500KBPS); + } else if (submode == static_cast(com::CcsdsSubmode::DATARATE_LOW)) { + result = ptmeConfig.setRate(RATE_100KBPS); + } + if (result != returnvalue::OK) { + sif::error << "CcsdsIpCoreHandler: Setting datarate failed" << std::endl; + } + updateContext.updateClockRate = false; + } + bool doResetPtme = true; + if (not updateContext.updateBatPrio and not updateContext.updateClockRate) { + doResetPtme = false; + } + finishPtmeUpdateAfterXCycles(doResetPtme); + return; + } + updateContext.ptmeUpdateCycleCount++; +} + +void CcsdsIpCoreHandler::resetPtme() { + gpioIF->pullLow(ptmeGpios.ptmeResetn); + usleep(10); + gpioIF->pullHigh(ptmeGpios.ptmeResetn); +} + +void CcsdsIpCoreHandler::initPtmeUpdateAfterXCycles() { + if (not updateContext.performPtmeUpdateAfterXCycles) { + updateContext.performPtmeUpdateAfterXCycles = true; + updateContext.ptmeUpdateCycleCount = 0; + ptmeLocked = true; + } +} + +void CcsdsIpCoreHandler::finishPtmeUpdateAfterXCycles(bool doResetPtme) { + if (doResetPtme) { + resetPtme(); + } + ptmeLocked = false; + updateContext.performPtmeUpdateAfterXCycles = false; + updateContext.ptmeUpdateCycleCount = 0; + if (updateContext.enableTransmitAfterPtmeUpdate) { + enableTransmit(); + updateContext.enableTransmitAfterPtmeUpdate = false; + } + if (updateContext.setModeAfterUpdate) { + setMode(mode, submode); + updateContext.setModeAfterUpdate = false; + } +} diff --git a/mission/com/CcsdsIpCoreHandler.h b/mission/com/CcsdsIpCoreHandler.h index 0fad0aae..785f84a5 100644 --- a/mission/com/CcsdsIpCoreHandler.h +++ b/mission/com/CcsdsIpCoreHandler.h @@ -2,7 +2,7 @@ #define CCSDSHANDLER_H_ #include -#include +#include #include #include @@ -79,7 +79,8 @@ class CcsdsIpCoreHandler : public SystemObject, * @param enTxData GPIO ID of RS485 tx data enable */ CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig, - std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds); + std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds, + std::atomic_bool& ptmeLocked); ~CcsdsIpCoreHandler(); @@ -137,9 +138,8 @@ class CcsdsIpCoreHandler : public SystemObject, //! [EXPORT] : [COMMENT] Received action message with unknown action id static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0); - // using VirtualChannelMap = std::unordered_map; - // VirtualChannelMap virtualChannelMap; std::atomic_bool& linkState; + std::atomic_bool& ptmeLocked; object_id_t tcDestination; @@ -158,7 +158,15 @@ class CcsdsIpCoreHandler : public SystemObject, PtmeGpios ptmeGpios; // BAT priority bit on by default to enable priority selection mode for the PTME. uint8_t batPriorityParam = 0; - bool updateBatPriorityOnTxOff = false; + + struct UpdateContext { + bool updateBatPrio = false; + bool updateClockRate = false; + bool enableTransmitAfterPtmeUpdate = false; + uint8_t ptmeUpdateCycleCount = 0; + bool performPtmeUpdateAfterXCycles = false; + bool setModeAfterUpdate = false; + } updateContext{}; GpioIF* gpioIF = nullptr; @@ -180,6 +188,8 @@ class CcsdsIpCoreHandler : public SystemObject, */ void disableTransmit(); + void performPtmeUpdateWhenApplicable(); + /** * The following set of functions configure the mode of the PTME bandwith allocation table (BAT) * module. This consists of the following 2 steps: @@ -189,6 +199,11 @@ class CcsdsIpCoreHandler : public SystemObject, void enablePrioritySelectMode(); void disablePrioritySelectMode(); void updateBatPriorityFromParam(); + + void setMode(Mode_t mode, Submode_t submode); + void resetPtme(); + void initPtmeUpdateAfterXCycles(); + void finishPtmeUpdateAfterXCycles(bool doResetPtme); }; #endif /* CCSDSHANDLER_H_ */ diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp new file mode 100644 index 00000000..d09c6ced --- /dev/null +++ b/mission/com/LiveTmTask.cpp @@ -0,0 +1,107 @@ +#include "LiveTmTask.h" + +#include +#include +#include +#include + +LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, + VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked) + : SystemObject(objectId), + modeHelper(this), + pusFunnel(pusFunnel), + cfdpFunnel(cfdpFunnel), + channel(channel), + ptmeLocked(ptmeLocked) { + requestQueue = QueueFactory::instance()->createMessageQueue(); +} + +ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { + readCommandQueue(); + while (true) { + bool performWriteOp = true; + if (mode == MODE_OFF or ptmeLocked) { + performWriteOp = false; + } + + // The funnel tasks are scheduled here directly as well. + ReturnValue_t result = channel.handleNextTm(performWriteOp); + if (result == DirectTmSinkIF::IS_BUSY) { + sif::error << "Lost live TM, PAPB busy" << std::endl; + } + if (result == MessageQueueIF::EMPTY) { + if (tmFunnelCd.hasTimedOut()) { + pusFunnel.performOperation(0); + cfdpFunnel.performOperation(0); + tmFunnelCd.resetTimer(); + } + // Read command queue during idle times. + readCommandQueue(); + // 40 ms IDLE delay. Might tweak this in the future. + TaskFactory::delayTask(40); + } else { + packetCounter++; + } + } +} + +MessageQueueId_t LiveTmTask::getCommandQueue() const { return requestQueue->getId(); } + +void LiveTmTask::getMode(Mode_t* mode, Submode_t* submode) { + if (mode != nullptr) { + *mode = this->mode; + } + if (submode != nullptr) { + *submode = SUBMODE_NONE; + } +} + +ReturnValue_t LiveTmTask::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) { + if (mode == MODE_ON or mode == MODE_OFF) { + return returnvalue::OK; + } + return returnvalue::FAILED; +} + +void LiveTmTask::startTransition(Mode_t mode, Submode_t submode) { + this->mode = mode; + modeHelper.modeChanged(mode, submode); + announceMode(false); +} + +void LiveTmTask::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); } + +object_id_t LiveTmTask::getObjectId() const { return SystemObject::getObjectId(); } + +const HasHealthIF* LiveTmTask::getOptHealthIF() const { return nullptr; } + +const HasModesIF& LiveTmTask::getModeIF() const { return *this; } + +ReturnValue_t LiveTmTask::connectModeTreeParent(HasModeTreeChildrenIF& parent) { + return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper); +} + +void LiveTmTask::readCommandQueue(void) { + CommandMessage commandMessage; + ReturnValue_t result = returnvalue::FAILED; + + result = requestQueue->receiveMessage(&commandMessage); + if (result == returnvalue::OK) { + result = modeHelper.handleModeCommand(&commandMessage); + if (result == returnvalue::OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); + requestQueue->reply(&reply); + return; + } +} + +ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; } + +ReturnValue_t LiveTmTask::initialize() { + modeHelper.initialize(); + return returnvalue::OK; +} diff --git a/mission/com/LiveTmTask.h b/mission/com/LiveTmTask.h new file mode 100644 index 00000000..c203f1de --- /dev/null +++ b/mission/com/LiveTmTask.h @@ -0,0 +1,57 @@ +#ifndef MISSION_TMTC_LIVETMTASK_H_ +#define MISSION_TMTC_LIVETMTASK_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LiveTmTask : public SystemObject, + public HasModesIF, + public ExecutableObjectIF, + public ModeTreeChildIF, + public ModeTreeConnectionIF { + public: + LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, + VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked); + + ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t initialize() override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; + + private: + MessageQueueIF* requestQueue; + ModeHelper modeHelper; + Mode_t mode = HasModesIF::MODE_OFF; + Countdown tmFunnelCd = Countdown(100); + PusTmFunnel& pusFunnel; + CfdpTmFunnel& cfdpFunnel; + VirtualChannelWithQueue& channel; + uint32_t packetCounter = 0; + const std::atomic_bool& ptmeLocked; + + void readCommandQueue(void); + + MessageQueueId_t getCommandQueue() const override; + + void getMode(Mode_t* mode, Submode_t* submode) override; + + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) override; + + void startTransition(Mode_t mode, Submode_t submode) override; + + void announceMode(bool recursive) override; + + object_id_t getObjectId() const override; + const HasHealthIF* getOptHealthIF() const override; + const HasModesIF& getModeIF() const override; + ModeTreeChildIF& getModeTreeChildIF() override; +}; + +#endif /* MISSION_TMTC_LIVETMTASK_H_ */ diff --git a/mission/com/PersistentLogTmStoreTask.cpp b/mission/com/PersistentLogTmStoreTask.cpp new file mode 100644 index 00000000..0fc02461 --- /dev/null +++ b/mission/com/PersistentLogTmStoreTask.cpp @@ -0,0 +1,74 @@ +#include "PersistentLogTmStoreTask.h" + +#include +#include + +PersistentLogTmStoreTask::PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, + LogStores stores, VirtualChannel& channel, + SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) + : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked), + stores(stores), + okStoreContext(persTmStore::DUMP_OK_STORE_DONE, persTmStore::DUMP_OK_CANCELLED), + notOkStoreContext(persTmStore::DUMP_NOK_STORE_DONE, persTmStore::DUMP_NOK_CANCELLED), + miscStoreContext(persTmStore::DUMP_MISC_STORE_DONE, persTmStore::DUMP_MISC_CANCELLED) {} + +ReturnValue_t PersistentLogTmStoreTask::performOperation(uint8_t opCode) { + bool someonesBusy = false; + bool vcBusyDuringDump = false; + auto stateHandlingForStore = [&](bool storeIsBusy, DumpContext& ctx) { + if (storeIsBusy) { + someonesBusy = true; + } + if (fileHasSwapped) { + someFileWasSwapped = fileHasSwapped; + } + if (ctx.vcBusyDuringDump) { + vcBusyDuringDump = true; + } + }; + while (true) { + readCommandQueue(); + + if (not cyclicStoreCheck()) { + continue; + } + someonesBusy = false; + someFileWasSwapped = false; + vcBusyDuringDump = false; + stateHandlingForStore(handleOneStore(stores.okStore, okStoreContext), okStoreContext); + stateHandlingForStore(handleOneStore(stores.notOkStore, notOkStoreContext), notOkStoreContext); + stateHandlingForStore(handleOneStore(stores.miscStore, miscStoreContext), miscStoreContext); + if (not someonesBusy) { + TaskFactory::delayTask(100); + } else if (vcBusyDuringDump) { + // TODO: Might not be necessary + sif::debug << "VC busy, delaying" << std::endl; + TaskFactory::delayTask(10); + } + } +} + +bool PersistentLogTmStoreTask::initStoresIfPossible() { + if (sdcMan.isSdCardUsable(std::nullopt)) { + stores.okStore.initializeTmStore(); + stores.miscStore.initializeTmStore(); + stores.notOkStore.initializeTmStore(); + return true; + } + return false; +} + +void PersistentLogTmStoreTask::startTransition(Mode_t mode, Submode_t submode) { + if (mode == MODE_OFF) { + bool channelIsOn = channel.isTxOn(); + cancelDump(okStoreContext, stores.okStore, channelIsOn); + cancelDump(notOkStoreContext, stores.notOkStore, channelIsOn); + cancelDump(miscStoreContext, stores.miscStore, channelIsOn); + this->mode = MODE_OFF; + } else if (mode == MODE_ON) { + this->mode = MODE_ON; + } + modeHelper.modeChanged(mode, submode); + announceMode(false); +} diff --git a/mission/tmtc/PersistentLogTmStoreTask.h b/mission/com/PersistentLogTmStoreTask.h similarity index 83% rename from mission/tmtc/PersistentLogTmStoreTask.h rename to mission/com/PersistentLogTmStoreTask.h index cb87ba6c..18da93f5 100644 --- a/mission/tmtc/PersistentLogTmStoreTask.h +++ b/mission/com/PersistentLogTmStoreTask.h @@ -5,11 +5,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include struct LogStores { LogStores(PersistentTmStores& stores) @@ -22,7 +22,8 @@ struct LogStores { class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF { public: PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, LogStores tmStore, - VirtualChannel& channel, SdCardMountedIF& sdcMan); + VirtualChannel& channel, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked); ReturnValue_t performOperation(uint8_t opCode) override; @@ -35,7 +36,8 @@ class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObject Countdown graceDelayDuringDumping = Countdown(200); bool someFileWasSwapped = false; - bool initStoresIfPossible(); + bool initStoresIfPossible() override; + void startTransition(Mode_t mode, Submode_t submode) override; }; #endif /* MISSION_TMTC_PERSISTENTLOGTMSTORETASK_H_ */ diff --git a/mission/com/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp new file mode 100644 index 00000000..615da659 --- /dev/null +++ b/mission/com/PersistentSingleTmStoreTask.cpp @@ -0,0 +1,54 @@ +#include "PersistentSingleTmStoreTask.h" + +#include +#include +#include + +PersistentSingleTmStoreTask::PersistentSingleTmStoreTask( + object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore, + VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) + : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked), + storeWithQueue(tmStore), + dumpContext(eventIfDumpDone, eventIfCancelled) {} + +ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) { + while (true) { + readCommandQueue(); + + // Delay done by the check + if (not cyclicStoreCheck()) { + continue; + } + bool busy = handleOneStore(storeWithQueue, dumpContext); + if (not busy) { + TaskFactory::delayTask(100); + } else if (dumpContext.vcBusyDuringDump) { + sif::debug << "VC busy, delaying" << std::endl; + // TODO: Might not be necessary + TaskFactory::delayTask(10); + } else { + // TODO: Would be best to remove this, but not delaying here can lead to evil issues. + TaskFactory::delayTask(10); + } + } +} + +bool PersistentSingleTmStoreTask::initStoresIfPossible() { + if (sdcMan.isSdCardUsable(std::nullopt)) { + storeWithQueue.initializeTmStore(); + return true; + } + return false; +} + +void PersistentSingleTmStoreTask::startTransition(Mode_t mode, Submode_t submode) { + if (mode == MODE_OFF) { + cancelDump(dumpContext, storeWithQueue, channel.isTxOn()); + this->mode = MODE_OFF; + } else if (mode == MODE_ON) { + this->mode = MODE_ON; + } + modeHelper.modeChanged(mode, submode); + announceMode(false); +} diff --git a/mission/tmtc/PersistentSingleTmStoreTask.h b/mission/com/PersistentSingleTmStoreTask.h similarity index 70% rename from mission/tmtc/PersistentSingleTmStoreTask.h rename to mission/com/PersistentSingleTmStoreTask.h index 7a4dd7ca..1a4c8683 100644 --- a/mission/tmtc/PersistentSingleTmStoreTask.h +++ b/mission/com/PersistentSingleTmStoreTask.h @@ -3,15 +3,16 @@ #include #include +#include +#include #include -#include -#include class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF { public: PersistentSingleTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& storeWithQueue, VirtualChannel& channel, - Event eventIfDumpDone, SdCardMountedIF& sdcMan); + Event eventIfDumpDone, Event eventIfCancelled, + SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked); ReturnValue_t performOperation(uint8_t opCode) override; @@ -21,7 +22,9 @@ class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObj Countdown tcHandlingCd = Countdown(400); Countdown graceDelayDuringDumping = Countdown(100); - bool initStoresIfPossible(); + bool initStoresIfPossible() override; + + void startTransition(Mode_t mode, Submode_t submode) override; }; #endif /* MISSION_TMTC_PERSISTENTSINGLETMSTORETASK_H_ */ diff --git a/mission/com/SyrlinksHandler.cpp b/mission/com/SyrlinksHandler.cpp index 5065f219..297ffd88 100644 --- a/mission/com/SyrlinksHandler.cpp +++ b/mission/com/SyrlinksHandler.cpp @@ -21,6 +21,7 @@ SyrlinksHandler::~SyrlinksHandler() = default; void SyrlinksHandler::doStartUp() { if (internalState == InternalState::OFF) { + transitionCommandPending = false; internalState = InternalState::ENABLE_TEMPERATURE_PROTECTION; commandExecuted = false; } @@ -38,6 +39,7 @@ void SyrlinksHandler::doShutDown() { // In any case, always disable TX first. if (internalState != InternalState::SET_TX_STANDBY) { internalState = InternalState::SET_TX_STANDBY; + transitionCommandPending = false; commandExecuted = false; } if (internalState == InternalState::SET_TX_STANDBY) { @@ -122,8 +124,9 @@ ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* i *id = syrlinks::SET_TX_MODE_STANDBY; return buildCommandFromCommand(*id, nullptr, 0); } - default: + default: { break; + } } return NOTHING_TO_SEND; } @@ -442,7 +445,6 @@ ReturnValue_t SyrlinksHandler::interpretDeviceReply(DeviceCommandId_t id, const return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; } } - return returnvalue::OK; } @@ -682,6 +684,9 @@ ReturnValue_t SyrlinksHandler::handleAckReply(const uint8_t* packet) { } break; } + default: { + sif::error << "Syrlinks: Unexpected ACK reply" << std::endl; + } } switch (rememberCommandId) { case (syrlinks::SET_TX_MODE_STANDBY): { @@ -728,16 +733,19 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { Mode_t tgtMode = getBaseMode(getMode()); auto commandDone = [&]() { setMode(tgtMode); + transitionCommandPending = false; internalState = InternalState::IDLE; }; auto txOnHandler = [&](InternalState selMod) { if (internalState == InternalState::IDLE) { + transitionCommandPending = false; commandExecuted = false; internalState = selMod; } // Select modulation first (BPSK or 0QPSK). if (internalState == selMod) { if (commandExecuted) { + transitionCommandPending = false; internalState = InternalState::SET_TX_MODULATION; commandExecuted = false; } @@ -753,6 +761,7 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { }; auto txStandbyHandler = [&]() { if (internalState == InternalState::IDLE) { + transitionCommandPending = false; internalState = InternalState::SET_TX_STANDBY; commandExecuted = false; } diff --git a/mission/com/SyrlinksHandler.h b/mission/com/SyrlinksHandler.h index 7d2d7227..97541ecb 100644 --- a/mission/com/SyrlinksHandler.h +++ b/mission/com/SyrlinksHandler.h @@ -112,6 +112,7 @@ class SyrlinksHandler : public DeviceHandlerBase { float tempPowerAmplifier = 0; float tempBasebandBoard = 0; bool commandExecuted = false; + bool transitionCommandPending = false; uint8_t commandBuffer[syrlinks::MAX_COMMAND_SIZE]; diff --git a/mission/com/TmStoreTaskBase.cpp b/mission/com/TmStoreTaskBase.cpp new file mode 100644 index 00000000..6598225d --- /dev/null +++ b/mission/com/TmStoreTaskBase.cpp @@ -0,0 +1,228 @@ +#include "TmStoreTaskBase.h" + +#include +#include +#include +#include +#include +#include + +#include "mission/persistentTmStoreDefs.h" + +TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, + VirtualChannel& channel, SdCardMountedIF& sdcMan, + const std::atomic_bool& ptmeLocked) + : SystemObject(objectId), + modeHelper(this), + ipcStore(ipcStore), + tmReader(&timeReader), + channel(channel), + sdcMan(sdcMan), + ptmeLocked(ptmeLocked) { + requestQueue = QueueFactory::instance()->createMessageQueue(10); +} + +bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, + DumpContext& dumpContext) { + ReturnValue_t result; + bool tmToStoreReceived = false; + bool tcRequestReceived = false; + bool dumpPerformed = false; + fileHasSwapped = false; + dumpContext.packetWasDumped = false; + dumpContext.vcBusyDuringDump = false; + + // Store TM persistently + result = store.handleNextTm(); + if (result == returnvalue::OK) { + tmToStoreReceived = true; + } + // Dump TMs + if (store.getState() == PersistentTmStore::State::DUMPING) { + if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) { + return result; + } + } else { + Command_t execCmd; + // Handle TC requests, for example deletion or retrieval requests. + result = store.handleCommandQueue(ipcStore, execCmd); + if (result == returnvalue::OK) { + if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) { + cancelDumpCd.resetTimer(); + tmSinkBusyCd.resetTimer(); + dumpContext.reset(); + } + tcRequestReceived = true; + } + } + if (tcRequestReceived or tmToStoreReceived or dumpPerformed) { + return true; + } + return false; +} + +bool TmStoreTaskBase::cyclicStoreCheck() { + if (not storesInitialized) { + storesInitialized = initStoresIfPossible(); + if (not storesInitialized) { + TaskFactory::delayTask(400); + return false; + } + } else if (sdCardCheckCd.hasTimedOut()) { + if (not sdcMan.isSdCardUsable(std::nullopt)) { + // Might be due to imminent shutdown or SD card switch. + storesInitialized = false; + TaskFactory::delayTask(100); + return false; + } + sdCardCheckCd.resetTimer(); + } + return true; +} + +void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn) { + ctx.reset(); + if (store.getState() == PersistentTmStore::State::DUMPING) { + triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes); + } + store.cancelDump(); + if (isTxOn) { + channel.cancelTransfer(); + } +} + +ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store, + DumpContext& dumpContext, bool& dumpPerformed) { + ReturnValue_t result = returnvalue::OK; + // The PTME might have been reset an transmitter state change, so there is no point in continuing + // the dump. + // TODO: Will be solved in a cleaner way, this is kind of a hack. + if (not channel.isTxOn()) { + cancelDump(dumpContext, store, false); + return returnvalue::FAILED; + } + // It is assumed that the PTME will only be locked for a short period (e.g. to change datarate). + if (not channel.isBusy() and not ptmeLocked) { + performDump(store, dumpContext, dumpPerformed); + } else { + // The PTME might be at full load, so it might sense to delay for a bit to let it do + // its work until some more bandwidth is available. Set a flag here so the upper layer can + // do ths. + dumpContext.vcBusyDuringDump = true; + dumpContext.ptmeBusyCounter++; + if (dumpContext.ptmeBusyCounter == 100) { + // If this happens, something is probably wrong. + sif::warning << "PTME busy for longer period. Cancelling dump" << std::endl; + cancelDump(dumpContext, store, channel.isTxOn()); + } + } + if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) { + cancelDump(dumpContext, store, channel.isTxOn()); + } + return result; +} + +ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store, + DumpContext& dumpContext, bool& dumpPerformed) { + size_t dumpedLen = 0; + + auto dumpDoneHandler = [&]() { + uint32_t startTime; + uint32_t endTime; + store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime); + triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets, + dumpContext.dumpedBytes); + dumpContext.reset(); + }; + // Dump the next packet into the PTME. + dumpContext.ptmeBusyCounter = 0; + tmSinkBusyCd.resetTimer(); + ReturnValue_t result = store.getNextDumpPacket(tmReader, fileHasSwapped); + if (result != returnvalue::OK) { + sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl; + } else if (fileHasSwapped or result == PersistentTmStore::DUMP_DONE) { + // This can happen if a file is corrupted and the next file swap completes the dump. + dumpDoneHandler(); + return returnvalue::OK; + } + dumpedLen = tmReader.getFullPacketLen(); + // Only write to VC if mode is on, but always confirm the dump. + // If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written + // (e.g. to confirm a reset or the transmitter is off anyway). + if (mode == MODE_ON) { + result = channel.write(tmReader.getFullData(), dumpedLen); + if (result == DirectTmSinkIF::IS_BUSY) { + sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl; + } else if (result != returnvalue::OK) { + sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl; + } + } + result = store.confirmDump(tmReader, fileHasSwapped); + if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK)) { + dumpPerformed = true; + if (dumpedLen > 0) { + dumpContext.dumpedBytes += dumpedLen; + dumpContext.numberOfDumpedPackets += 1; + dumpContext.packetWasDumped = true; + } + } + if (result == PersistentTmStore::DUMP_DONE) { + dumpDoneHandler(); + } + return returnvalue::OK; +} + +ReturnValue_t TmStoreTaskBase::initialize() { + modeHelper.initialize(); + return returnvalue::OK; +} + +void TmStoreTaskBase::getMode(Mode_t* mode, Submode_t* submode) { + if (mode != nullptr) { + *mode = this->mode; + } + if (submode != nullptr) { + *submode = SUBMODE_NONE; + } +} + +ReturnValue_t TmStoreTaskBase::checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) { + if (mode == MODE_ON or mode == MODE_OFF) { + return returnvalue::OK; + } + return returnvalue::FAILED; +} + +MessageQueueId_t TmStoreTaskBase::getCommandQueue() const { return requestQueue->getId(); } + +void TmStoreTaskBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); } + +object_id_t TmStoreTaskBase::getObjectId() const { return SystemObject::getObjectId(); } + +const HasHealthIF* TmStoreTaskBase::getOptHealthIF() const { return nullptr; } + +const HasModesIF& TmStoreTaskBase::getModeIF() const { return *this; } + +ReturnValue_t TmStoreTaskBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) { + return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper); +} + +ModeTreeChildIF& TmStoreTaskBase::getModeTreeChildIF() { return *this; } + +void TmStoreTaskBase::readCommandQueue(void) { + CommandMessage commandMessage; + ReturnValue_t result = returnvalue::FAILED; + + result = requestQueue->receiveMessage(&commandMessage); + if (result == returnvalue::OK) { + result = modeHelper.handleModeCommand(&commandMessage); + if (result == returnvalue::OK) { + return; + } + CommandMessage reply; + reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); + requestQueue->reply(&reply); + return; + } +} diff --git a/mission/com/TmStoreTaskBase.h b/mission/com/TmStoreTaskBase.h new file mode 100644 index 00000000..ef61bd19 --- /dev/null +++ b/mission/com/TmStoreTaskBase.h @@ -0,0 +1,106 @@ +#ifndef MISSION_TMTC_TMSTORETASKBASE_H_ +#define MISSION_TMTC_TMSTORETASKBASE_H_ + +#include +#include +#include +#include +#include +#include +#include + +/** + * Generic class which composes a Virtual Channel and a persistent TM stores. This allows dumping + * the TM store into the virtual channel directly. + */ +class TmStoreTaskBase : public SystemObject, + public HasModesIF, + public ModeTreeChildIF, + public ModeTreeConnectionIF { + public: + struct DumpContext { + DumpContext(Event eventIfDone, Event eventIfCancelled) + : eventIfDone(eventIfDone), eventIfCancelled(eventIfCancelled) {} + void reset() { + numberOfDumpedPackets = 0; + dumpedBytes = 0; + vcBusyDuringDump = false; + packetWasDumped = false; + bytesDumpedAtLastDelay = 0; + ptmeBusyCounter = 0; + } + const Event eventIfDone; + const Event eventIfCancelled; + size_t numberOfDumpedPackets = 0; + size_t bytesDumpedAtLastDelay = 0; + size_t dumpedBytes = 0; + uint32_t ptmeBusyCounter = 0; + bool packetWasDumped = false; + bool vcBusyDuringDump = false; + }; + + TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel, + SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked); + + ReturnValue_t initialize() override; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override; + + protected: + ModeHelper modeHelper; + MessageQueueIF* requestQueue; + StorageManagerIF& ipcStore; + PusTmReader tmReader; + CdsShortTimeStamper timeReader; + VirtualChannel& channel; + SdCardMountedIF& sdcMan; + const std::atomic_bool& ptmeLocked; + + Mode_t mode = HasModesIF::MODE_OFF; + Countdown sdCardCheckCd = Countdown(800); + // 20 minutes are allowed as maximum dump time. + Countdown cancelDumpCd = Countdown(60 * 20 * 1000); + // If the TM sink is busy for 1 minute for whatever reason, cancel the dump. + Countdown tmSinkBusyCd = Countdown(60 * 1000); + + bool storesInitialized = false; + bool fileHasSwapped = false; + + void readCommandQueue(void); + + virtual bool initStoresIfPossible() = 0; + virtual void startTransition(Mode_t mode, Submode_t submode) = 0; + + void cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn); + /** + * + * Handling for one store. Returns if anything was done. + * @param store + * @return + */ + bool handleOneStore(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext); + + ReturnValue_t handleOneDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext, + bool& dumpPerformed); + ReturnValue_t performDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext, + bool& dumpPerformed); + + /** + * Occasionally check whether SD card is okay to be used. If not, poll whether it is ready to + * be used again and re-initialize stores. Returns whether store is okay to be used. + */ + bool cyclicStoreCheck(); + + MessageQueueId_t getCommandQueue() const override; + + void getMode(Mode_t* mode, Submode_t* submode) override; + + ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, + uint32_t* msToReachTheMode) override; + void announceMode(bool recursive) override; + object_id_t getObjectId() const override; + const HasHealthIF* getOptHealthIF() const override; + const HasModesIF& getModeIF() const override; + ModeTreeChildIF& getModeTreeChildIF() override; +}; + +#endif /* MISSION_TMTC_TMSTORETASKBASE_H_ */ diff --git a/mission/tmtc/VirtualChannel.cpp b/mission/com/VirtualChannel.cpp similarity index 74% rename from mission/tmtc/VirtualChannel.cpp rename to mission/com/VirtualChannel.cpp index 4fed30b1..8e225674 100644 --- a/mission/tmtc/VirtualChannel.cpp +++ b/mission/com/VirtualChannel.cpp @@ -1,12 +1,8 @@ #include "VirtualChannel.h" VirtualChannel::VirtualChannel(object_id_t objectId, uint8_t vcId, const char* vcName, PtmeIF& ptme, - const std::atomic_bool& linkStateProvider) - : SystemObject(objectId), - ptme(ptme), - vcId(vcId), - vcName(vcName), - linkStateProvider(linkStateProvider) {} + const std::atomic_bool& txOn) + : SystemObject(objectId), ptme(ptme), vcId(vcId), vcName(vcName), txOn(txOn) {} ReturnValue_t VirtualChannel::initialize() { return returnvalue::OK; } @@ -15,7 +11,7 @@ ReturnValue_t VirtualChannel::sendNextTm(const uint8_t* data, size_t size) { } ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size) { - if (linkStateProvider.load()) { + if (txOn) { return ptme.writeToVc(vcId, data, size); } return returnvalue::OK; @@ -27,10 +23,12 @@ const char* VirtualChannel::getName() const { return vcName.c_str(); } bool VirtualChannel::isBusy() const { // Data is discarded, so channel is not busy. - if (linkStateProvider.load()) { + if (not txOn) { return false; } return ptme.isBusy(vcId); } void VirtualChannel::cancelTransfer() { ptme.cancelTransfer(vcId); } + +bool VirtualChannel::isTxOn() const { return txOn; } diff --git a/mission/tmtc/VirtualChannel.h b/mission/com/VirtualChannel.h similarity index 95% rename from mission/tmtc/VirtualChannel.h rename to mission/com/VirtualChannel.h index 4cad3305..98aba903 100644 --- a/mission/tmtc/VirtualChannel.h +++ b/mission/com/VirtualChannel.h @@ -30,6 +30,7 @@ class VirtualChannel : public SystemObject, public VirtualChannelIF { ReturnValue_t write(const uint8_t* data, size_t size) override; void cancelTransfer() override; uint8_t getVcid() const; + bool isTxOn() const; const char* getName() const; @@ -37,5 +38,5 @@ class VirtualChannel : public SystemObject, public VirtualChannelIF { PtmeIF& ptme; uint8_t vcId = 0; std::string vcName; - const std::atomic_bool& linkStateProvider; + const std::atomic_bool& txOn; }; diff --git a/mission/tmtc/VirtualChannelWithQueue.cpp b/mission/com/VirtualChannelWithQueue.cpp similarity index 84% rename from mission/tmtc/VirtualChannelWithQueue.cpp rename to mission/com/VirtualChannelWithQueue.cpp index bfc74907..a90829ab 100644 --- a/mission/tmtc/VirtualChannelWithQueue.cpp +++ b/mission/com/VirtualChannelWithQueue.cpp @@ -1,4 +1,4 @@ -#include +#include "VirtualChannelWithQueue.h" #include "OBSWConfig.h" #include "fsfw/ipc/QueueFactory.h" @@ -19,7 +19,7 @@ VirtualChannelWithQueue::VirtualChannelWithQueue(object_id_t objectId, uint8_t v const char* VirtualChannelWithQueue::getName() const { return VirtualChannel::getName(); } -ReturnValue_t VirtualChannelWithQueue::sendNextTm() { +ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) { TmTcMessage message; ReturnValue_t result = tmQueue->receiveMessage(&message); if (result == MessageQueueIF::EMPTY) { @@ -36,15 +36,13 @@ ReturnValue_t VirtualChannelWithQueue::sendNextTm() { return result; } - result = write(data, size); - if (result != returnvalue::OK) { - return result; + if (performWriteOp) { + result = write(data, size); } + // Try delete in any case, ignore failures (which should not happen), it is more important to + // propagate write errors. tmStore.deleteData(storeId); - if (result != returnvalue::OK) { - return result; - } - return returnvalue::OK; + return result; } MessageQueueId_t VirtualChannelWithQueue::getReportReceptionQueue(uint8_t virtualChannel) const { diff --git a/mission/tmtc/VirtualChannelWithQueue.h b/mission/com/VirtualChannelWithQueue.h similarity index 93% rename from mission/tmtc/VirtualChannelWithQueue.h rename to mission/com/VirtualChannelWithQueue.h index 0c060a06..04c7f965 100644 --- a/mission/tmtc/VirtualChannelWithQueue.h +++ b/mission/com/VirtualChannelWithQueue.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include @@ -34,7 +34,7 @@ class VirtualChannelWithQueue : public VirtualChannel, public AcceptsTelemetryIF MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override; [[nodiscard]] const char* getName() const override; - ReturnValue_t sendNextTm(); + ReturnValue_t handleNextTm(bool performWriteOp); private: MessageQueueIF* tmQueue = nullptr; diff --git a/mission/config/comCfg.cpp b/mission/config/comCfg.cpp index 8387214d..664a2e55 100644 --- a/mission/config/comCfg.cpp +++ b/mission/config/comCfg.cpp @@ -3,6 +3,8 @@ #include #include +#include + com::Datarate DATARATE_CFG_RAW = com::Datarate::LOW_RATE_MODULATION_BPSK; MutexIF* DATARATE_LOCK = nullptr; diff --git a/mission/genericFactory.cpp b/mission/genericFactory.cpp index d4cfe798..0ae2ead3 100644 --- a/mission/genericFactory.cpp +++ b/mission/genericFactory.cpp @@ -347,7 +347,8 @@ void ObjectFactory::createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, AcsBoardHelper acsBoardHelper = AcsBoardHelper( objects::MGM_0_LIS3_HANDLER, objects::MGM_1_RM3100_HANDLER, objects::MGM_2_LIS3_HANDLER, objects::MGM_3_RM3100_HANDLER, objects::GYRO_0_ADIS_HANDLER, objects::GYRO_1_L3G_HANDLER, - objects::GYRO_2_ADIS_HANDLER, objects::GYRO_3_L3G_HANDLER, objects::GPS_CONTROLLER); + objects::GYRO_2_ADIS_HANDLER, objects::GYRO_3_L3G_HANDLER, objects::GPS_CONTROLLER, + objects::GPS_0_HEALTH_DEV, objects::GPS_1_HEALTH_DEV); auto acsAss = new AcsBoardAssembly(objects::ACS_BOARD_ASS, &pwrSwitcher, acsBoardHelper, gpioComIF); for (auto& assChild : assemblyDhbs) { diff --git a/mission/payload/ScexDeviceHandler.cpp b/mission/payload/ScexDeviceHandler.cpp index 7ef070a9..2b3f69f7 100644 --- a/mission/payload/ScexDeviceHandler.cpp +++ b/mission/payload/ScexDeviceHandler.cpp @@ -205,7 +205,7 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons using namespace scex; ReturnValue_t status = OK; - auto oneFileHandler = [&](std::string cmdName) { + auto oneFileHandler = [&](const char* cmdName) { auto activeSd = sdcMan.getActiveSdCard(); if (not activeSd) { return HasFileSystemIF::FILESYSTEM_INACTIVE; @@ -216,7 +216,7 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons if (prefix == nullptr) { return returnvalue::FAILED; } - oss << prefix << "/scex/scex-" << cmdName << fileId << ".bin"; + oss << prefix << "/scex/scex-" << cmdName << "-" << fileId << ".bin"; fileName = oss.str(); ofstream out(fileName, ofstream::binary); if (out.bad()) { @@ -227,7 +227,7 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons out << helper; return OK; }; - auto multiFileHandler = [&](std::string cmdName) { + auto multiFileHandler = [&](const char* cmdName) { if ((helper.getPacketCounter() == 1) or (not fileNameSet)) { auto activeSd = sdcMan.getActiveSdCard(); if (not activeSd) { @@ -264,31 +264,31 @@ ReturnValue_t ScexDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, cons id = helper.getCmd(); switch (id) { case (PING): { - status = oneFileHandler("ping_"); + status = oneFileHandler(PING_IDLE_BASE_NAME); break; } case (ION_CMD): { - status = oneFileHandler("ion_"); + status = oneFileHandler(ION_BASE_NAME); break; } case (TEMP_CMD): { - status = oneFileHandler("temp_"); + status = oneFileHandler(TEMPERATURE_BASE_NAME); break; } case (EXP_STATUS_CMD): { - status = oneFileHandler("exp_status_"); + status = oneFileHandler(EXP_STATUS_BASE_NAME); break; } case (FRAM): { - status = multiFileHandler("fram_"); + status = multiFileHandler(FRAM_BASE_NAME); break; } case (ONE_CELL): { - status = multiFileHandler("one_cell_"); + status = multiFileHandler(ONE_CELL_BASE_NAME); break; } case (ALL_CELLS_CMD): { - status = multiFileHandler("multi_cell_"); + status = multiFileHandler(ALL_CELLS_BASE_NAME); break; } default: @@ -362,9 +362,9 @@ std::string ScexDeviceHandler::date_time_string() { ostringstream oss(std::ostringstream::ate); if (tod.hour < 10) { - oss << tod.year << tod.month << tod.day << "_0" << tod.hour; + oss << tod.year << tod.month << tod.day << "T0" << tod.hour; } else { - oss << tod.year << tod.month << tod.day << "_" << tod.hour; + oss << tod.year << tod.month << tod.day << "T" << tod.hour; } if (tod.minute < 10) { oss << 0 << tod.minute; diff --git a/mission/payload/ScexDeviceHandler.h b/mission/payload/ScexDeviceHandler.h index 089a9005..f95169b9 100644 --- a/mission/payload/ScexDeviceHandler.h +++ b/mission/payload/ScexDeviceHandler.h @@ -13,6 +13,14 @@ class SdCardMountedIF; class ScexDeviceHandler : public DeviceHandlerBase { public: + static constexpr char FRAM_BASE_NAME[] = "framContent"; + static constexpr char ION_BASE_NAME[] = "ion"; + static constexpr char TEMPERATURE_BASE_NAME[] = "temperature"; + static constexpr char EXP_STATUS_BASE_NAME[] = "expStatus"; + static constexpr char ONE_CELL_BASE_NAME[] = "oneCell"; + static constexpr char ALL_CELLS_BASE_NAME[] = "allCells"; + static constexpr char PING_IDLE_BASE_NAME[] = "pingIdle"; + ScexDeviceHandler(object_id_t objectId, ScexUartReader &reader, CookieIF *cookie, SdCardMountedIF &sdcMan); void setPowerSwitcher(PowerSwitchIF &powerSwitcher, power::Switch_t switchId); diff --git a/mission/persistentTmStoreDefs.h b/mission/persistentTmStoreDefs.h index 2498536d..8b8873de 100644 --- a/mission/persistentTmStoreDefs.h +++ b/mission/persistentTmStoreDefs.h @@ -25,8 +25,6 @@ static constexpr Event POSSIBLE_FILE_CORRUPTION = event::makeEvent(SUBSYSTEM_ID, //! P2: Allowed file size static constexpr Event FILE_TOO_LARGE = event::makeEvent(SUBSYSTEM_ID, 1, severity::LOW); static constexpr Event BUSY_DUMPING_EVENT = event::makeEvent(SUBSYSTEM_ID, 2, severity::INFO); -//! [EXPORT] : [COMMENT] Dump was cancelled. P1: Object ID of store. -static constexpr Event DUMP_WAS_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 3, severity::LOW); //! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. static constexpr Event DUMP_OK_STORE_DONE = event::makeEvent(SUBSYSTEM_ID, 5, severity::INFO); @@ -38,6 +36,17 @@ static constexpr Event DUMP_MISC_STORE_DONE = event::makeEvent(SUBSYSTEM_ID, 7, static constexpr Event DUMP_HK_STORE_DONE = event::makeEvent(SUBSYSTEM_ID, 8, severity::INFO); //! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. static constexpr Event DUMP_CFDP_STORE_DONE = event::makeEvent(SUBSYSTEM_ID, 9, severity::INFO); + +//! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. +static constexpr Event DUMP_OK_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 10, severity::LOW); +//! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. +static constexpr Event DUMP_NOK_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 11, severity::LOW); +//! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. +static constexpr Event DUMP_MISC_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 12, severity::LOW); +//! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. +static constexpr Event DUMP_HK_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 13, severity::LOW); +//! [EXPORT] : [COMMENT] P1: Number of dumped packets. P2: Total dumped bytes. +static constexpr Event DUMP_CFDP_CANCELLED = event::makeEvent(SUBSYSTEM_ID, 14, severity::LOW); }; // namespace persTmStore #endif /* MISSION_PERSISTENTTMSTOREDEFS_H_ */ diff --git a/mission/pollingSeqTables.cpp b/mission/pollingSeqTables.cpp index 8d172132..4225e977 100644 --- a/mission/pollingSeqTables.cpp +++ b/mission/pollingSeqTables.cpp @@ -26,10 +26,12 @@ ReturnValue_t pst::pstSyrlinks(FixedTimeslotTaskIF *thisSequence) { thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, + DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ); static_cast(length); diff --git a/mission/system/acs/AcsBoardAssembly.cpp b/mission/system/acs/AcsBoardAssembly.cpp index 2441beda..6c4023f8 100644 --- a/mission/system/acs/AcsBoardAssembly.cpp +++ b/mission/system/acs/AcsBoardAssembly.cpp @@ -77,14 +77,16 @@ ReturnValue_t AcsBoardAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_ if (wantedSubmode == A_SIDE) { if ((helper.gyro0SideAMode != wantedMode and helper.gyro1SideAMode != wantedMode) or (helper.mgm0SideAMode != wantedMode and helper.mgm1SideAMode != wantedMode) or - helper.gpsMode != MODE_ON) { + (helper.gpsMode != MODE_ON) or + (healthHelper.healthTable->getHealth(helper.healthDevGps0) == FAULTY)) { return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; } return returnvalue::OK; } else if (wantedSubmode == B_SIDE) { if ((helper.gyro2SideBMode != wantedMode and helper.gyro3SideBMode != wantedMode) or (helper.mgm2SideBMode != wantedMode and helper.mgm3SideBMode != wantedMode) or - helper.gpsMode != MODE_ON) { + (helper.gpsMode != MODE_ON) or + (healthHelper.healthTable->getHealth(helper.healthDevGps1) == FAULTY)) { return NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE; } return returnvalue::OK; @@ -126,12 +128,33 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s auto cmdSeq = [&](object_id_t objectId, Mode_t devMode, ModeTableIdx tableIdx) { if (mode == devMode) { modeTable[tableIdx].setMode(mode); - } else if (isUseable(objectId, devMode)) { + } else if (isModeCommandable(objectId, devMode)) { modeTable[tableIdx].setMode(mode); modeTable[tableIdx].setSubmode(SUBMODE_NONE); } }; - bool gpsUsable = isUseable(helper.gpsId, helper.gpsMode); + bool gpsUsable = isModeCommandable(helper.gpsId, helper.gpsMode); + auto gpsCmd = [&](bool gnss0NReset, bool gnss1NReset, uint8_t gnssSelect) { + if (gpsUsable) { + if (mode == MODE_ON or mode == DeviceHandlerIF::MODE_NORMAL) { + modeTable[ModeTableIdx::GPS].setMode(MODE_ON); + } else if (mode == MODE_OFF) { + gnss0NReset = true; + gnss1NReset = true; + modeTable[ModeTableIdx::GPS].setMode(MODE_OFF); + } + modeTable[ModeTableIdx::GPS].setSubmode(SUBMODE_NONE); + + gpioHandler(gpioIds::GNSS_0_NRESET, gnss0NReset, + "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" + "of GNSS 0"); + gpioHandler(gpioIds::GNSS_1_NRESET, gnss1NReset, + "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" + "of GNSS 1"); + gpioHandler(gpioIds::GNSS_SELECT, gnssSelect, + "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull GNSS select"); + } + }; switch (submode) { case (A_SIDE): { modeTable[ModeTableIdx::GYRO_2_B].setMode(MODE_OFF); @@ -146,16 +169,7 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s cmdSeq(helper.gyro1L3gIdSideA, helper.gyro1SideAMode, ModeTableIdx::GYRO_1_A); cmdSeq(helper.mgm0Lis3IdSideA, helper.mgm0SideAMode, ModeTableIdx::MGM_0_A); cmdSeq(helper.mgm1Rm3100IdSideA, helper.mgm1SideAMode, ModeTableIdx::MGM_1_A); - if (gpsUsable) { - gpioHandler(gpioIds::GNSS_0_NRESET, true, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 0 high (used GNSS)"); - gpioHandler(gpioIds::GNSS_1_NRESET, false, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 1 low (unused GNSS)"); - gpioHandler(gpioIds::GNSS_SELECT, false, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull GNSS select low"); - } + gpsCmd(true, false, 0); break; } case (B_SIDE): { @@ -171,20 +185,10 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s cmdSeq(helper.gyro3L3gIdSideB, helper.gyro3SideBMode, ModeTableIdx::GYRO_3_B); cmdSeq(helper.mgm2Lis3IdSideB, helper.mgm2SideBMode, ModeTableIdx::MGM_2_B); cmdSeq(helper.mgm3Rm3100IdSideB, helper.mgm3SideBMode, ModeTableIdx::MGM_3_B); - if (gpsUsable) { - gpioHandler(gpioIds::GNSS_0_NRESET, false, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 0 low (unused GNSS)"); - gpioHandler(gpioIds::GNSS_1_NRESET, true, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 1 high (used GNSS)"); - gpioHandler(gpioIds::GNSS_SELECT, true, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull GNSS select high"); - } + gpsCmd(false, true, 1); break; } case (DUAL_MODE): { - cmdSeq(helper.gpsId, helper.gpsMode, ModeTableIdx::GPS); cmdSeq(helper.gyro0AdisIdSideA, helper.gyro0SideAMode, ModeTableIdx::GYRO_0_A); cmdSeq(helper.gyro1L3gIdSideA, helper.gyro1SideAMode, ModeTableIdx::GYRO_1_A); cmdSeq(helper.mgm0Lis3IdSideA, helper.mgm0SideAMode, ModeTableIdx::MGM_0_A); @@ -193,26 +197,10 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s cmdSeq(helper.gyro3L3gIdSideB, helper.gyro3SideBMode, ModeTableIdx::GYRO_3_B); cmdSeq(helper.mgm2Lis3IdSideB, helper.mgm2SideBMode, ModeTableIdx::MGM_2_B); cmdSeq(helper.mgm3Rm3100IdSideB, helper.mgm3SideBMode, ModeTableIdx::MGM_3_B); - ReturnValue_t status = returnvalue::OK; - if (gpsUsable) { - gpioHandler(gpioIds::GNSS_0_NRESET, true, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 0 high (used GNSS)"); - gpioHandler(gpioIds::GNSS_1_NRESET, true, - "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull nReset pin" - "of GNSS 1 high (used GNSS)"); - if (defaultSubmode == Submodes::A_SIDE) { - status = gpioIF->pullLow(gpioIds::GNSS_SELECT); - } else { - status = gpioIF->pullHigh(gpioIds::GNSS_SELECT); - } - if (status != returnvalue::OK) { -#if OBSW_VERBOSE_LEVEL >= 1 - sif::error << "AcsBoardAssembly::handleNormalOrOnModeCmd: Could not pull GNSS select to" - "default side for dual mode" - << std::endl; -#endif - } + if (defaultSubmode == Submodes::A_SIDE) { + gpsCmd(true, true, 0); + } else { + gpsCmd(true, true, 1); } break; } @@ -220,10 +208,6 @@ ReturnValue_t AcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s sif::error << "AcsBoardAssembly::handleNormalModeCmd: Unknown submode" << std::endl; } } - if (gpsUsable) { - modeTable[ModeTableIdx::GPS].setMode(MODE_ON); - modeTable[ModeTableIdx::GPS].setSubmode(SUBMODE_NONE); - } if (needsSecondStep) { result = NEED_SECOND_STEP; } @@ -289,25 +273,54 @@ ReturnValue_t AcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode) { using namespace returnvalue; ReturnValue_t status = returnvalue::OK; - auto overwriteHealthForOneDev = [&](object_id_t dev) { - HealthState health = healthHelper.healthTable->getHealth(dev); - if (health == FAULTY or health == PERMANENT_FAULTY) { - overwriteDeviceHealth(dev, health); - status = NEED_TO_CHANGE_HEALTH; - } else if (health == EXTERNAL_CONTROL) { + auto checkAcsBoardSensorGroup = [&](object_id_t o0, object_id_t o1, object_id_t o2, + object_id_t o3) { + HealthState h0 = healthHelper.healthTable->getHealth(o0); + HealthState h1 = healthHelper.healthTable->getHealth(o1); + HealthState h2 = healthHelper.healthTable->getHealth(o2); + HealthState h3 = healthHelper.healthTable->getHealth(o3); + if ((h0 == FAULTY or h0 == PERMANENT_FAULTY) and (h1 == FAULTY or h1 == PERMANENT_FAULTY) and + (h2 == FAULTY or h2 == PERMANENT_FAULTY) and (h3 == FAULTY or h3 == PERMANENT_FAULTY)) { + overwriteDeviceHealth(o0, h0); + overwriteDeviceHealth(o1, h1); + overwriteDeviceHealth(o2, h2); + overwriteDeviceHealth(o3, h3); + } + if (h0 == EXTERNAL_CONTROL or h1 == EXTERNAL_CONTROL or h2 == EXTERNAL_CONTROL or + h3 == EXTERNAL_CONTROL) { modeHelper.setForced(true); } }; + if (healthHelper.healthTable->getHealth(helper.gpsId) == EXTERNAL_CONTROL) { + modeHelper.setForced(true); + } if (deviceSubmode == duallane::DUAL_MODE) { - overwriteHealthForOneDev(helper.mgm0Lis3IdSideA); - overwriteHealthForOneDev(helper.mgm1Rm3100IdSideA); - overwriteHealthForOneDev(helper.mgm2Lis3IdSideB); - overwriteHealthForOneDev(helper.mgm3Rm3100IdSideB); - overwriteHealthForOneDev(helper.gyro0AdisIdSideA); - overwriteHealthForOneDev(helper.gyro1L3gIdSideA); - overwriteHealthForOneDev(helper.gyro2AdisIdSideB); - overwriteHealthForOneDev(helper.gyro3L3gIdSideB); - overwriteHealthForOneDev(helper.gpsId); + checkAcsBoardSensorGroup(helper.mgm0Lis3IdSideA, helper.mgm1Rm3100IdSideA, + helper.mgm2Lis3IdSideB, helper.mgm3Rm3100IdSideB); + checkAcsBoardSensorGroup(helper.gyro0AdisIdSideA, helper.gyro1L3gIdSideA, + helper.gyro2AdisIdSideB, helper.gyro3L3gIdSideB); } return status; } + +void AcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) { + using namespace duallane; + // Special handling to account for GPS devices being faulty. If the GPS device on the other + // side is marked faulty, directly to to dual side. + if (submode == Submodes::A_SIDE) { + if (healthHelper.healthTable->getHealth(helper.healthDevGps1) == FAULTY or + healthHelper.healthTable->getHealth(helper.healthDevGps1) == PERMANENT_FAULTY) { + triggerEvent(DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY, submode, 0); + startTransition(mode, Submodes::DUAL_MODE); + return; + } + } else if (submode == Submodes::B_SIDE) { + if (healthHelper.healthTable->getHealth(helper.healthDevGps0) == FAULTY or + healthHelper.healthTable->getHealth(helper.healthDevGps0) == PERMANENT_FAULTY) { + triggerEvent(DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY, submode, 0); + startTransition(mode, Submodes::DUAL_MODE); + return; + } + } + DualLaneAssemblyBase::handleChildrenLostMode(result); +} diff --git a/mission/system/acs/AcsBoardAssembly.h b/mission/system/acs/AcsBoardAssembly.h index c6a37c79..6619dadb 100644 --- a/mission/system/acs/AcsBoardAssembly.h +++ b/mission/system/acs/AcsBoardAssembly.h @@ -12,7 +12,7 @@ struct AcsBoardHelper { AcsBoardHelper(object_id_t mgm0Id, object_id_t mgm1Id, object_id_t mgm2Id, object_id_t mgm3Id, object_id_t gyro0Id, object_id_t gyro1Id, object_id_t gyro2Id, object_id_t gyro3Id, - object_id_t gpsId) + object_id_t gpsId, object_id_t gps0HealthDev, object_id_t gps1HealthDev) : mgm0Lis3IdSideA(mgm0Id), mgm1Rm3100IdSideA(mgm1Id), mgm2Lis3IdSideB(mgm2Id), @@ -35,6 +35,9 @@ struct AcsBoardHelper { object_id_t gpsId = objects::NO_OBJECT; + object_id_t healthDevGps0 = objects::NO_OBJECT; + object_id_t healthDevGps1 = objects::NO_OBJECT; + Mode_t gyro0SideAMode = HasModesIF::MODE_OFF; Mode_t gyro1SideAMode = HasModesIF::MODE_OFF; Mode_t gyro2SideBMode = HasModesIF::MODE_OFF; @@ -91,6 +94,11 @@ class AcsBoardAssembly : public DualLaneAssemblyBase { //! desired mode/submode combination static constexpr Event SIDE_SWITCH_TRANSITION_NOT_ALLOWED = event::makeEvent(SUBSYSTEM_ID, 3, severity::LOW); + //! [EXPORT] : [COMMENT] This is triggered when the assembly would have normally switched + //! the board side, but the GPS device of the other side was marked faulty. + //! P1: Current submode. + static constexpr Event DIRECT_TRANSITION_TO_DUAL_OTHER_GPS_FAULTY = + event::makeEvent(SUBSYSTEM_ID, 4, severity::MEDIUM); static constexpr uint8_t NUMBER_DEVICES_MODE_TABLE = 9; @@ -120,6 +128,8 @@ class AcsBoardAssembly : public DualLaneAssemblyBase { ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override; + void handleChildrenLostMode(ReturnValue_t result) override; + ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode); ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode); void refreshHelperModes(); diff --git a/mission/system/acs/CMakeLists.txt b/mission/system/acs/CMakeLists.txt index 70e11e59..e5ef2cb8 100644 --- a/mission/system/acs/CMakeLists.txt +++ b/mission/system/acs/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources( ${LIB_EIVE_MISSION} PRIVATE AcsBoardAssembly.cpp AcsSubsystem.cpp + StrAssembly.cpp DualLaneAssemblyBase.cpp ImtqAssembly.cpp RwAssembly.cpp diff --git a/mission/system/acs/DualLaneAssemblyBase.cpp b/mission/system/acs/DualLaneAssemblyBase.cpp index c4182594..e1ef29cc 100644 --- a/mission/system/acs/DualLaneAssemblyBase.cpp +++ b/mission/system/acs/DualLaneAssemblyBase.cpp @@ -46,6 +46,9 @@ void DualLaneAssemblyBase::startTransition(Mode_t mode, Submode_t submode) { AssemblyBase::startTransition(mode, submode); return; } + if (sideSwitchState == SideSwitchState::NONE and sideSwitchTransition(mode, submode)) { + sideSwitchState = SideSwitchState::REQUESTED; + } uint8_t pwrSubmode = submode; if (sideSwitchState == SideSwitchState::REQUESTED) { pwrSubmode = duallane::DUAL_MODE; @@ -61,7 +64,7 @@ void DualLaneAssemblyBase::startTransition(Mode_t mode, Submode_t submode) { } } -bool DualLaneAssemblyBase::isUseable(object_id_t object, Mode_t mode) { +bool DualLaneAssemblyBase::isModeCommandable(object_id_t object, Mode_t mode) { if (healthHelper.healthTable->isFaulty(object)) { return false; } @@ -70,10 +73,7 @@ bool DualLaneAssemblyBase::isUseable(object_id_t object, Mode_t mode) { if (childrenMap[object].mode == mode) { return true; } - - if (healthHelper.healthTable->isCommandable(object)) { - return true; - } + // Check for external control health state is done by base class. return false; } @@ -115,9 +115,6 @@ ReturnValue_t DualLaneAssemblyBase::isModeCombinationValid(Mode_t mode, Submode_ if (submode != A_SIDE and submode != B_SIDE and submode != DUAL_MODE) { return returnvalue::FAILED; } - if (sideSwitchTransition(mode, submode)) { - sideSwitchState = SideSwitchState::REQUESTED; - } return returnvalue::OK; } diff --git a/mission/system/acs/DualLaneAssemblyBase.h b/mission/system/acs/DualLaneAssemblyBase.h index a6739af2..485f3d9d 100644 --- a/mission/system/acs/DualLaneAssemblyBase.h +++ b/mission/system/acs/DualLaneAssemblyBase.h @@ -49,12 +49,12 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF { MessageQueueIF* eventQueue = nullptr; /** - * Check whether it makes sense to send mode commands to the device + * Check whether it makes sense to send mode commands to the device. * @param object * @param mode * @return */ - bool isUseable(object_id_t object, Mode_t mode); + bool isModeCommandable(object_id_t object, Mode_t mode); /** * Thin wrapper function which is required because the helper class diff --git a/mission/system/objects/StrAssembly.cpp b/mission/system/acs/StrAssembly.cpp similarity index 100% rename from mission/system/objects/StrAssembly.cpp rename to mission/system/acs/StrAssembly.cpp diff --git a/mission/system/objects/StrAssembly.h b/mission/system/acs/StrAssembly.h similarity index 100% rename from mission/system/objects/StrAssembly.h rename to mission/system/acs/StrAssembly.h diff --git a/mission/system/acs/SusAssembly.cpp b/mission/system/acs/SusAssembly.cpp index 9008e7e0..45123ce4 100644 --- a/mission/system/acs/SusAssembly.cpp +++ b/mission/system/acs/SusAssembly.cpp @@ -158,18 +158,29 @@ void SusAssembly::refreshHelperModes() { ReturnValue_t SusAssembly::checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode) { using namespace returnvalue; ReturnValue_t status = returnvalue::OK; - auto overwriteHealthForOneDev = [&](object_id_t dev) { + auto checkSusGroup = [&](object_id_t devNom, object_id_t devRed) { + HealthState healthNom = healthHelper.healthTable->getHealth(devNom); + HealthState healthRed = healthHelper.healthTable->getHealth(devRed); + if ((healthNom == FAULTY or healthNom == PERMANENT_FAULTY) and + (healthRed == FAULTY or healthRed == PERMANENT_FAULTY)) { + overwriteDeviceHealth(devNom, healthNom); + overwriteDeviceHealth(devRed, healthRed); + } + }; + auto checkHealthForOneDev = [&](object_id_t dev) { HealthState health = healthHelper.healthTable->getHealth(dev); - if (health == FAULTY or health == PERMANENT_FAULTY) { - overwriteDeviceHealth(dev, health); - status = NEED_TO_CHANGE_HEALTH; - } else if (health == EXTERNAL_CONTROL) { + if (health == EXTERNAL_CONTROL) { modeHelper.setForced(true); } }; if (deviceSubmode == duallane::DUAL_MODE) { - for (uint8_t idx = 0; idx < 12; idx++) { - overwriteHealthForOneDev(helper.susIds[idx]); + uint8_t idx = 0; + for (idx = 0; idx < 6; idx++) { + checkSusGroup(helper.susIds[idx], helper.susIds[idx + 6]); + checkHealthForOneDev(helper.susIds[idx]); + } + for (idx = 6; idx < 12; idx++) { + checkHealthForOneDev(helper.susIds[idx]); } } return status; diff --git a/mission/system/com/comModeTree.cpp b/mission/system/com/comModeTree.cpp index 9501262d..bb9a8d10 100644 --- a/mission/system/com/comModeTree.cpp +++ b/mission/system/com/comModeTree.cpp @@ -22,7 +22,7 @@ auto COM_SEQUENCE_RX_ONLY = auto COM_TABLE_RX_ONLY_TGT = std::make_pair( static_cast(::com::Submode::RX_ONLY << 24) | 1, FixedArrayList()); auto COM_TABLE_RX_ONLY_TRANS_0 = std::make_pair( - static_cast(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList()); + static_cast(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList()); auto COM_TABLE_RX_ONLY_TRANS_1 = std::make_pair( static_cast(::com::Submode::RX_ONLY << 24) | 3, FixedArrayList()); @@ -36,7 +36,7 @@ auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_LOW_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); auto COM_SEQUENCE_RX_AND_TX_HIGH_RATE = std::make_pair(::com::Submode::RX_AND_TX_HIGH_DATARATE, FixedArrayList()); @@ -48,7 +48,7 @@ auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_HIGH_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); auto COM_SEQUENCE_RX_AND_TX_DEFAULT_RATE = std::make_pair(::com::Submode::RX_AND_TX_DEFAULT_DATARATE, FixedArrayList()); @@ -60,7 +60,7 @@ auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_0 = FixedArrayList()); auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1 = std::make_pair(static_cast(::com::Submode::RX_AND_TX_DEFAULT_DATARATE << 24) | 3, - FixedArrayList()); + FixedArrayList()); namespace { @@ -110,6 +110,10 @@ void buildRxOnlySequence(Subsystem& ss, ModeListEntry& eh) { // Build RX Only transition 0 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_ONLY, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::LOG_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::HK_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::CFDP_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); + iht(objects::LIVE_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second); check(ss.addTable(TableEntry(COM_TABLE_RX_ONLY_TRANS_0.first, &COM_TABLE_RX_ONLY_TRANS_0.second)), ctxc); @@ -165,6 +169,10 @@ void buildTxAndRxLowRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX low transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_LOW_DATARATE, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second)), ctxc); @@ -217,6 +225,10 @@ void buildTxAndRxHighRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX high transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_HIGH_DATARATE, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second)), ctxc); @@ -271,6 +283,10 @@ void buildTxAndRxDefaultRateSequence(Subsystem& ss, ModeListEntry& eh) { // Build TX and RX default transition 1 iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_DEFAULT_DATARATE, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); + iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second); check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.first, &COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second)), ctxc); diff --git a/mission/system/objects/CMakeLists.txt b/mission/system/objects/CMakeLists.txt index e23a82c7..53cc200d 100644 --- a/mission/system/objects/CMakeLists.txt +++ b/mission/system/objects/CMakeLists.txt @@ -5,6 +5,5 @@ target_sources( TcsSubsystem.cpp PayloadSubsystem.cpp Stack5VHandler.cpp - StrAssembly.cpp PowerStateMachineBase.cpp TcsBoardAssembly.cpp) diff --git a/mission/tmtc/CMakeLists.txt b/mission/tmtc/CMakeLists.txt index c797e315..a8388d83 100644 --- a/mission/tmtc/CMakeLists.txt +++ b/mission/tmtc/CMakeLists.txt @@ -1,17 +1,11 @@ target_sources( ${LIB_EIVE_MISSION} - PRIVATE VirtualChannelWithQueue.cpp - PersistentTmStoreWithTmQueue.cpp - LiveTmTask.cpp - VirtualChannel.cpp + PRIVATE PersistentTmStoreWithTmQueue.cpp TmFunnelHandler.cpp TmFunnelBase.cpp CfdpTmFunnel.cpp tmFilters.cpp PusLiveDemux.cpp - PersistentSingleTmStoreTask.cpp - PersistentLogTmStoreTask.cpp - TmStoreTaskBase.cpp PusPacketFilter.cpp PusTmRouteByFilterHelper.cpp Service15TmStorage.cpp diff --git a/mission/tmtc/LiveTmTask.cpp b/mission/tmtc/LiveTmTask.cpp deleted file mode 100644 index 7e6d3de6..00000000 --- a/mission/tmtc/LiveTmTask.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "LiveTmTask.h" - -#include -#include - -LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel) - : SystemObject(objectId), pusFunnel(pusFunnel), cfdpFunnel(cfdpFunnel), channel(channel) {} - -ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { - while (true) { - // The funnel tasks are scheduled here directly as well. - ReturnValue_t result = channel.sendNextTm(); - if (result == DirectTmSinkIF::IS_BUSY) { - sif::error << "Lost live TM, PAPB busy" << std::endl; - } - if (result == MessageQueueIF::EMPTY) { - if (tmFunnelCd.hasTimedOut()) { - pusFunnel.performOperation(0); - cfdpFunnel.performOperation(0); - tmFunnelCd.resetTimer(); - } - // 40 ms IDLE delay. Might tweak this in the future. - TaskFactory::delayTask(40); - } - } -} diff --git a/mission/tmtc/LiveTmTask.h b/mission/tmtc/LiveTmTask.h deleted file mode 100644 index a0ca6b83..00000000 --- a/mission/tmtc/LiveTmTask.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MISSION_TMTC_LIVETMTASK_H_ -#define MISSION_TMTC_LIVETMTASK_H_ - -#include -#include -#include -#include -#include -#include - -class LiveTmTask : public SystemObject, public ExecutableObjectIF { - public: - LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, - VirtualChannelWithQueue& channel); - - ReturnValue_t performOperation(uint8_t opCode) override; - - private: - Countdown tmFunnelCd = Countdown(100); - PusTmFunnel& pusFunnel; - CfdpTmFunnel& cfdpFunnel; - VirtualChannelWithQueue& channel; -}; - -#endif /* MISSION_TMTC_LIVETMTASK_H_ */ diff --git a/mission/tmtc/PersistentLogTmStoreTask.cpp b/mission/tmtc/PersistentLogTmStoreTask.cpp deleted file mode 100644 index 1faba222..00000000 --- a/mission/tmtc/PersistentLogTmStoreTask.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "PersistentLogTmStoreTask.h" - -#include -#include - -PersistentLogTmStoreTask::PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, - LogStores stores, VirtualChannel& channel, - SdCardMountedIF& sdcMan) - : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), - stores(stores), - okStoreContext(persTmStore::DUMP_OK_STORE_DONE), - notOkStoreContext(persTmStore::DUMP_NOK_STORE_DONE), - miscStoreContext(persTmStore::DUMP_MISC_STORE_DONE) {} - -ReturnValue_t PersistentLogTmStoreTask::performOperation(uint8_t opCode) { - bool someonesBusy = false; - auto stateHandlingForStore = [&](bool storeIsBusy) { - if (storeIsBusy) { - someonesBusy = true; - } - if (fileHasSwapped) { - someFileWasSwapped = fileHasSwapped; - } - }; - while (true) { - if (not cyclicStoreCheck()) { - continue; - } - someonesBusy = false; - someFileWasSwapped = false; - stateHandlingForStore(handleOneStore(stores.okStore, okStoreContext)); - stateHandlingForStore(handleOneStore(stores.notOkStore, notOkStoreContext)); - stateHandlingForStore(handleOneStore(stores.miscStore, miscStoreContext)); - if (not someonesBusy) { - TaskFactory::delayTask(100); - } else if (someFileWasSwapped) { - TaskFactory::delayTask(10); - } - } -} - -bool PersistentLogTmStoreTask::initStoresIfPossible() { - if (sdcMan.isSdCardUsable(std::nullopt)) { - stores.okStore.initializeTmStore(); - stores.miscStore.initializeTmStore(); - stores.notOkStore.initializeTmStore(); - return true; - } - return false; -} diff --git a/mission/tmtc/PersistentSingleTmStoreTask.cpp b/mission/tmtc/PersistentSingleTmStoreTask.cpp deleted file mode 100644 index be300d91..00000000 --- a/mission/tmtc/PersistentSingleTmStoreTask.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -PersistentSingleTmStoreTask::PersistentSingleTmStoreTask( - object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore, - VirtualChannel& channel, Event eventIfDumpDone, SdCardMountedIF& sdcMan) - : TmStoreTaskBase(objectId, ipcStore, channel, sdcMan), - storeWithQueue(tmStore), - dumpContext(eventIfDumpDone) {} - -ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) { - while (true) { - // Delay done by the check - if (not cyclicStoreCheck()) { - continue; - } - bool busy = handleOneStore(storeWithQueue, dumpContext); - if (not busy) { - TaskFactory::delayTask(100); - } else if (fileHasSwapped) { - TaskFactory::delayTask(10); - } - } -} - -bool PersistentSingleTmStoreTask::initStoresIfPossible() { - if (sdcMan.isSdCardUsable(std::nullopt)) { - storeWithQueue.initializeTmStore(); - return true; - } - return false; -} diff --git a/mission/tmtc/PersistentTmStore.cpp b/mission/tmtc/PersistentTmStore.cpp index 6cbcac86..a5f0ec66 100644 --- a/mission/tmtc/PersistentTmStore.cpp +++ b/mission/tmtc/PersistentTmStore.cpp @@ -171,7 +171,7 @@ void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) { // Convert file time to the UNIX epoch struct tm fileTime {}; if (pathToTime(file.path(), fileTime) != returnvalue::OK) { - sif::error << "Time extraction for " << file << "failed" << std::endl; + sif::error << "Time extraction for " << file << " failed" << std::endl; continue; } time_t fileEpoch = timegm(&fileTime); @@ -212,7 +212,7 @@ ReturnValue_t PersistentTmStore::loadNextDumpFile() { sif::error << "PersistentTmStore: Could not retrieve file size: " << e.message() << std::endl; continue; } - sif::debug << "Path: " << dumpParams.dirEntry.path() << std::endl; + // sif::debug << "Path: " << dumpParams.dirEntry.path() << std::endl; // File empty or can't even read CCSDS header. if (dumpParams.fileSize <= 6) { @@ -251,41 +251,37 @@ ReturnValue_t PersistentTmStore::loadNextDumpFile() { return DUMP_DONE; } -ReturnValue_t PersistentTmStore::dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen, - bool& fileHasSwapped) { - if (state == State::IDLE) { +ReturnValue_t PersistentTmStore::getNextDumpPacket(PusTmReader& reader, bool& fileHasSwapped) { + if (state == State::IDLE or dumpParams.pendingPacketDump) { return returnvalue::FAILED; } - PusTmReader reader(&timeReader, fileBuf.data() + dumpParams.currentSize, - fileBuf.size() - dumpParams.currentSize); + reader.setReadOnlyData(fileBuf.data() + dumpParams.currentSize, + fileBuf.size() - dumpParams.currentSize); // CRC check to fully ensure this is a valid TM ReturnValue_t result = reader.parseDataWithCrcCheck(); - if (result == returnvalue::OK) { - result = tmSink.write(fileBuf.data() + dumpParams.currentSize, reader.getFullPacketLen()); - if (result == DirectTmSinkIF::IS_BUSY) { - return result; - } else if (result != returnvalue::OK) { - // TODO: Event? - sif::error << "PersistentTmStore: Writing to TM sink failed" << std::endl; - return result; - } - dumpParams.currentSize += reader.getFullPacketLen(); - dumpedLen = reader.getFullPacketLen(); - if (dumpParams.currentSize >= dumpParams.fileSize) { - fileHasSwapped = true; - return loadNextDumpFile(); - } - } else { + if (result != returnvalue::OK) { sif::error << "PersistentTmStore: Parsing of PUS TM failed with code " << result << std::endl; triggerEvent(persTmStore::POSSIBLE_FILE_CORRUPTION, result, dumpParams.currentFileUnixStamp); // Delete the file and load next. Could use better algorithm to partially // restore the file dump, but for now do not trust the file. - dumpedLen = 0; std::error_code e; std::filesystem::remove(dumpParams.dirEntry.path().c_str(), e); fileHasSwapped = true; return loadNextDumpFile(); } + fileHasSwapped = false; + dumpParams.pendingPacketDump = true; + return returnvalue::OK; +} + +ReturnValue_t PersistentTmStore::confirmDump(const PusTmReader& reader, bool& fileHasSwapped) { + dumpParams.pendingPacketDump = false; + dumpParams.currentSize += reader.getFullPacketLen(); + if (dumpParams.currentSize >= dumpParams.fileSize) { + fileHasSwapped = true; + return loadNextDumpFile(); + } + fileHasSwapped = false; return returnvalue::OK; } diff --git a/mission/tmtc/PersistentTmStore.h b/mission/tmtc/PersistentTmStore.h index a0910026..4839f2fb 100644 --- a/mission/tmtc/PersistentTmStore.h +++ b/mission/tmtc/PersistentTmStore.h @@ -4,12 +4,10 @@ #include #include #include -#include #include #include #include #include -#include #include @@ -57,13 +55,25 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds); /** * - * @param tmSink - * @param dumpedLen - * @param fileHasSwapped - * @return DUMP_DONE if dump is finished, returnvalue::OK if dump of next packet was a success, - * and DirectTmSinkIF::IS_BUSY is TM sink is busy. + * @param tmReader: Next packet will be loaded into the PUS TM reader. A CRC check will be + * performed on the packet. If that check fails, the file is considered corrupted and will + * be deleted for now. + * @param fileHasSwapped: If the CRC check fails, the file will be deleted and a new one has to + * be loaded. The dump can reach completion during that process. If a file is swapped, this + * boolean is set to true + * @return DUMP_DONE if dump is finished, returnvalue::OK if the next packet was loaded into the + * TM reader, and the returnvalue of the file swap operation if the CRC check failed and + * a new file was loaded. */ - ReturnValue_t dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen, bool& fileHasSwapped); + ReturnValue_t getNextDumpPacket(PusTmReader& tmReader, bool& fileHasSwapped); + /** + * Confirm the dump to advance the dump state machine. + * @param tmReader + * @param fileHasSwapped: If the confirmed dumps completes the current file, a new file will + * be loaded and this parameter will be set to true. + * @return If a file is swapped, the retrunvalue of the file swap operation. + */ + ReturnValue_t confirmDump(const PusTmReader& tmReader, bool& fileHasSwapped); void getStartAndEndTimeCurrentOrLastDump(uint32_t& startTime, uint32_t& endTime) const; ReturnValue_t storePacket(PusTmReader& reader); @@ -83,8 +93,6 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { MessageQueueIF* tcQueue; State state = State::IDLE; - // PacketFilter filter; - CdsShortTimeStamper timeReader; bool baseDirUninitialized = true; const char* baseDir; std::string baseName; @@ -96,6 +104,7 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject { timeval activeFileTv{}; struct ActiveDumpParams { + bool pendingPacketDump = false; uint32_t fromUnixTime = 0; uint32_t untilUnixTime = 0; uint32_t currentFileUnixStamp = 0; diff --git a/mission/tmtc/TmStoreTaskBase.cpp b/mission/tmtc/TmStoreTaskBase.cpp deleted file mode 100644 index eefe9dc6..00000000 --- a/mission/tmtc/TmStoreTaskBase.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "TmStoreTaskBase.h" - -#include -#include -#include -#include - -#include "mission/persistentTmStoreDefs.h" - -TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, - VirtualChannel& channel, SdCardMountedIF& sdcMan) - : SystemObject(objectId), ipcStore(ipcStore), channel(channel), sdcMan(sdcMan) {} - -bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store, - DumpContext& dumpContext) { - ReturnValue_t result; - bool tmToStoreReceived = false; - bool tcRequestReceived = false; - bool dumpsPerformed = false; - // Store TM persistently - result = store.handleNextTm(); - if (result == returnvalue::OK) { - tmToStoreReceived = true; - } - // Dump TMs when applicable - if (store.getState() == PersistentTmStore::State::DUMPING) { - size_t dumpedLen = 0; - if (not channel.isBusy()) { - tmSinkBusyCd.resetTimer(); - result = store.dumpNextPacket(channel, dumpedLen, fileHasSwapped); - if (result == DirectTmSinkIF::IS_BUSY) { - sif::warning << "Unexpected PAPB busy" << std::endl; - } - if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK) and dumpedLen > 0) { - dumpContext.dumpedBytes += dumpedLen; - dumpContext.numberOfDumpedPackets += 1; - } - if (result == PersistentTmStore::DUMP_DONE) { - uint32_t startTime; - uint32_t endTime; - store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime); - triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets, - dumpContext.dumpedBytes); - dumpsPerformed = true; - } else if (result == returnvalue::OK) { - dumpsPerformed = true; - } - } else { - dumpContext.ptmeBusyCounter++; - if (dumpContext.ptmeBusyCounter == 50) { - sif::warning << "PTME busy for longer period. Dumped length so far: " - << dumpContext.dumpedBytes << std::endl; - dumpContext.ptmeBusyCounter = 0; - } - } - if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) { - triggerEvent(persTmStore::DUMP_WAS_CANCELLED, store.getObjectId()); - store.cancelDump(); - } - } else { - Command_t execCmd; - // Handle TC requests, for example deletion or retrieval requests. - result = store.handleCommandQueue(ipcStore, execCmd); - if (result == returnvalue::OK) { - if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) { - cancelDumpCd.resetTimer(); - tmSinkBusyCd.resetTimer(); - dumpContext.reset(); - } - tcRequestReceived = true; - } - } - if (tcRequestReceived or tmToStoreReceived or dumpsPerformed) { - return true; - } - return false; -} - -bool TmStoreTaskBase::cyclicStoreCheck() { - if (not storesInitialized) { - storesInitialized = initStoresIfPossible(); - if (not storesInitialized) { - TaskFactory::delayTask(400); - return false; - } - } else if (sdCardCheckCd.hasTimedOut()) { - if (not sdcMan.isSdCardUsable(std::nullopt)) { - // Might be due to imminent shutdown or SD card switch. - storesInitialized = false; - TaskFactory::delayTask(100); - return false; - } - sdCardCheckCd.resetTimer(); - } - return true; -} diff --git a/mission/tmtc/TmStoreTaskBase.h b/mission/tmtc/TmStoreTaskBase.h deleted file mode 100644 index aa0efbb4..00000000 --- a/mission/tmtc/TmStoreTaskBase.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef MISSION_TMTC_TMSTORETASKBASE_H_ -#define MISSION_TMTC_TMSTORETASKBASE_H_ - -#include -#include -#include - -class TmStoreTaskBase : public SystemObject { - public: - struct DumpContext { - DumpContext(Event eventIfDone) : eventIfDone(eventIfDone) {} - void reset() { - numberOfDumpedPackets = 0; - dumpedBytes = 0; - } - const Event eventIfDone; - uint32_t numberOfDumpedPackets = 0; - uint32_t dumpedBytes = 0; - uint32_t ptmeBusyCounter = 0; - }; - - TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel, - SdCardMountedIF& sdcMan); - - protected: - /** - * Handling for one store. Returns if anything was done. - * @param store - * @return - */ - bool handleOneStore(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext); - - /** - * Occasionally check whether SD card is okay to be used. If not, poll whether it is ready to - * be used again and re-initialize stores. Returns whether store is okay to be used. - */ - bool cyclicStoreCheck(); - - virtual bool initStoresIfPossible() = 0; - - StorageManagerIF& ipcStore; - Countdown sdCardCheckCd = Countdown(800); - // 20 minutes are allowed as maximum dump time. - Countdown cancelDumpCd = Countdown(60 * 20 * 1000); - // If the TM sink is busy for 1 minute for whatever reason, cancel the dump. - Countdown tmSinkBusyCd = Countdown(60 * 1000); - VirtualChannel& channel; - bool storesInitialized = false; - bool fileHasSwapped = false; - SdCardMountedIF& sdcMan; -}; - -#endif /* MISSION_TMTC_TMSTORETASKBASE_H_ */ diff --git a/tmtc b/tmtc index f2897fa6..523dd9b7 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit f2897fa6060e178ef8d11c9d29faa058896c9253 +Subproject commit 523dd9b759a57c5bff2ae9221eee303dfa080558