diff --git a/CHANGELOG.md b/CHANGELOG.md index 9956115d..be62180f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ will consitute of a breaking change warranting a new major release: temperature for the all-ones value (0x0fff). - Better reply result handling for the ACS board devices. - ADIS1650X initial timeout handling now performed in device handler. +- The RW assembly and TCS board assembly now perform proper power switch handling for their + recovery handling. ## Changed @@ -33,6 +35,8 @@ will consitute of a breaking change warranting a new major release: the active SD card is switched or there is a transition from hot redundant to cold redundant mode. This gives other tasks some time to register the SD cards being unusable, and therefore provides a way for them to perform any re-initialization tasks necessary after SD card switches. +- The TCS controller pauses operations related to the TCS board assembly (reading sensors and + the primary control loop) while a TCS board recovery is on-going. ## Changed diff --git a/dummies/helperFactory.cpp b/dummies/helperFactory.cpp index 404b640c..f2323bee 100644 --- a/dummies/helperFactory.cpp +++ b/dummies/helperFactory.cpp @@ -40,6 +40,7 @@ #include "mission/system/com/comModeTree.h" #include "mission/system/tree/payloadModeTree.h" #include "mission/system/tree/tcsModeTree.h" +#include "mission/tcs/defs.h" void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) { new ComIFDummy(objects::DUMMY_COM_IF); @@ -202,7 +203,8 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio new TemperatureSensorInserter(objects::THERMAL_TEMP_INSERTER, rtdSensorDummies, tmpSensorDummies); - TcsBoardAssembly* tcsBoardAssy = ObjectFactory::createTcsBoardAssy(pwrSwitcher); + TcsBoardAssembly* tcsBoardAssy = + ObjectFactory::createTcsBoardAssy(pwrSwitcher, tcs::TCS_BOARD_SHORTLY_UNAVAILABLE); for (auto& rtd : rtdSensorDummies) { rtd.second->connectModeTreeParent(*tcsBoardAssy); } diff --git a/linux/ObjectFactory.cpp b/linux/ObjectFactory.cpp index 66a3195b..72f30278 100644 --- a/linux/ObjectFactory.cpp +++ b/linux/ObjectFactory.cpp @@ -29,6 +29,7 @@ #include "mission/system/acs/acsModeTree.h" #include "mission/system/tree/payloadModeTree.h" #include "mission/system/tree/tcsModeTree.h" +#include "mission/tcs/defs.h" void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF, PowerSwitchIF& pwrSwitcher, std::string spiDev, @@ -278,7 +279,8 @@ void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF, std::array rtds = {}; RtdFdir* rtdFdir = nullptr; - TcsBoardAssembly* tcsBoardAss = ObjectFactory::createTcsBoardAssy(*pwrSwitcher); + TcsBoardAssembly* tcsBoardAss = + ObjectFactory::createTcsBoardAssy(*pwrSwitcher, tcs::TCS_BOARD_SHORTLY_UNAVAILABLE); // Create special low level reader communication interface new Max31865RtdPolling(objects::SPI_RTD_COM_IF, comIF, gpioComIF); diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 96b6de86..fc2da4ef 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -21,7 +21,8 @@ #define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_PLOC_UPPER_LIMITS 0 -ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater) +ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater, + const std::atomic_bool& tcsBoardShortUnavailable) : ExtendedControllerBase(objectId), heaterHandler(heater), sensorTemperatures(this), @@ -66,7 +67,8 @@ ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater susSet8(objects::SUS_8_R_LOC_XBYBZB_PT_YB), susSet9(objects::SUS_9_R_LOC_XBYBZB_PT_YF), susSet10(objects::SUS_10_N_LOC_XMYBZF_PT_ZF), - susSet11(objects::SUS_11_R_LOC_XBYMZB_PT_ZB) { + susSet11(objects::SUS_11_R_LOC_XBYMZB_PT_ZB), + tcsBrdShortlyUnavailable(tcsBoardShortUnavailable) { resetSensorsArray(); } @@ -134,10 +136,12 @@ void ThermalController::performControlOperation() { } } - { - PoolReadGuard pg(&sensorTemperatures); - if (pg.getReadResult() == returnvalue::OK) { - copySensors(); + if (not tcsBrdShortlyUnavailable) { + { + PoolReadGuard pg(&sensorTemperatures); + if (pg.getReadResult() == returnvalue::OK) { + copySensors(); + } } } { @@ -182,7 +186,7 @@ void ThermalController::performControlOperation() { } setMode(MODE_OFF); } - } else if (mode != MODE_OFF) { + } else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) { performThermalModuleCtrl(heaterSwitchStateArray); } cycles++; diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index 631a37aa..54b05216 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -22,6 +22,7 @@ #include #include +#include #include /** @@ -94,7 +95,8 @@ class ThermalController : public ExtendedControllerBase { static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160; - ThermalController(object_id_t objectId, HeaterHandler& heater); + ThermalController(object_id_t objectId, HeaterHandler& heater, + const std::atomic_bool& tcsBoardShortUnavailable); ReturnValue_t initialize() override; @@ -181,6 +183,10 @@ class ThermalController : public ExtendedControllerBase { susMax1227::SusDataset susSet10; susMax1227::SusDataset susSet11; + // If the TCS board in unavailable, for example due to a recovery, skip + // some TCS controller tasks to avoid unnecessary events. + const std::atomic_bool& tcsBrdShortlyUnavailable = false; + lp_var_t tempQ7s = lp_var_t(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE); lp_var_t battTemp1 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1); lp_var_t battTemp2 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2); diff --git a/mission/genericFactory.cpp b/mission/genericFactory.cpp index ce338097..61063372 100644 --- a/mission/genericFactory.cpp +++ b/mission/genericFactory.cpp @@ -48,6 +48,7 @@ #include "mission/system/acs/RwAssembly.h" #include "mission/system/acs/acsModeTree.h" #include "mission/system/tree/tcsModeTree.h" +#include "mission/tcs/defs.h" #include "mission/tmtc/tmFilters.h" #include "objects/systemObjectList.h" #include "tmtc/pusIds.h" @@ -90,6 +91,8 @@ EiveFaultHandler EIVE_FAULT_HANDLER; } // namespace cfdp +std::atomic_bool tcs::TCS_BOARD_SHORTLY_UNAVAILABLE = false; + void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel, CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan, StorageManagerIF** ipcStore, StorageManagerIF** tmStore, @@ -300,7 +303,8 @@ void ObjectFactory::createGenericHeaterComponents(GpioIF& gpioIF, PowerSwitchIF& } void ObjectFactory::createThermalController(HeaterHandler& heaterHandler) { - auto* tcsCtrl = new ThermalController(objects::THERMAL_CONTROLLER, heaterHandler); + auto* tcsCtrl = new ThermalController(objects::THERMAL_CONTROLLER, heaterHandler, + tcs::TCS_BOARD_SHORTLY_UNAVAILABLE); tcsCtrl->connectModeTreeParent(satsystem::tcs::SUBSYSTEM); } void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch, @@ -366,10 +370,12 @@ void ObjectFactory::createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, acsAss->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM); } -TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher) { +TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher, + std::atomic_bool& tcsShortlyUnavailable) { TcsBoardHelper helper(RTD_INFOS); - auto* tcsBoardAss = new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher, - power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper); + auto* tcsBoardAss = + new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher, + power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper, tcsShortlyUnavailable); tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM); return tcsBoardAss; } diff --git a/mission/genericFactory.h b/mission/genericFactory.h index 496c516b..6cd2068d 100644 --- a/mission/genericFactory.h +++ b/mission/genericFactory.h @@ -55,7 +55,8 @@ void createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch, void createSusAssy(PowerSwitchIF& pwrSwitcher, std::array suses); void createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, std::array assemblyDhbs, ExtendedControllerBase* gpsCtrl, GpioIF* gpioComIF); -TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher); +TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher, + std::atomic_bool& tcsShortlyUnavailable); } // namespace ObjectFactory diff --git a/mission/power/defs.h b/mission/power/defs.h index b10fe1ff..13e5e63f 100644 --- a/mission/power/defs.h +++ b/mission/power/defs.h @@ -50,6 +50,7 @@ static constexpr Event FDIR_REACTION_IGNORED = event::makeEvent(SUBSYSTEM_ID, 3, enum class States { IDLE, SWITCHING_POWER, CHECKING_POWER, MODE_COMMANDING }; enum class OpCodes { NONE, TO_OFF_DONE, TO_NOT_OFF_DONE, TIMEOUT_OCCURED }; +enum RecoveryCustomStates { IDLE, POWER_SWITCHING_OFF, POWER_SWITCHING_ON, DONE }; } // namespace power namespace duallane { diff --git a/mission/system/CMakeLists.txt b/mission/system/CMakeLists.txt index 51e47ef4..e5473de8 100644 --- a/mission/system/CMakeLists.txt +++ b/mission/system/CMakeLists.txt @@ -6,5 +6,6 @@ add_subdirectory(fdir) add_subdirectory(power) target_sources( - ${LIB_EIVE_MISSION} PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp - EiveSystem.cpp treeUtil.cpp) + ${LIB_EIVE_MISSION} + PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp EiveSystem.cpp + treeUtil.cpp SharedPowerAssemblyBase.cpp) diff --git a/mission/system/SharedPowerAssemblyBase.cpp b/mission/system/SharedPowerAssemblyBase.cpp new file mode 100644 index 00000000..5c325b51 --- /dev/null +++ b/mission/system/SharedPowerAssemblyBase.cpp @@ -0,0 +1,91 @@ +#include "SharedPowerAssemblyBase.h" + +SharedPowerAssemblyBase::SharedPowerAssemblyBase(object_id_t objectId, PowerSwitchIF* pwrSwitcher, + power::Switch_t switchId, uint16_t cmdQueueDepth) + : AssemblyBase(objectId, cmdQueueDepth), switcher(pwrSwitcher, switchId) {} + +void SharedPowerAssemblyBase::performChildOperation() { + auto state = switcher.getState(); + if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) { + AssemblyBase::performChildOperation(); + return; + } + switcher.doStateMachine(); + if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { + // Indicator that a transition to off is finished + AssemblyBase::handleModeReached(); + } else if (state == PowerSwitcher::WAIT_ON and + switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { + // Indicator that mode commanding can be performed now + AssemblyBase::startTransition(targetMode, targetSubmode); + } +} + +void SharedPowerAssemblyBase::startTransition(Mode_t mode, Submode_t submode) { + if (mode != MODE_OFF) { + switcher.turnOn(true); + switcher.doStateMachine(); + if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { + AssemblyBase::startTransition(mode, submode); + } else { + // Need to wait with mode commanding until power switcher is done + targetMode = mode; + targetSubmode = submode; + } + } else { + // Perform regular mode commanding first + AssemblyBase::startTransition(mode, submode); + } +} + +void SharedPowerAssemblyBase::handleModeReached() { + if (targetMode == MODE_OFF) { + switcher.turnOff(true); + switcher.doStateMachine(); + // Need to wait with call to AssemblyBase::handleModeReached until power switcher is done + if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { + AssemblyBase::handleModeReached(); + } + } else { + AssemblyBase::handleModeReached(); + } +} + +bool SharedPowerAssemblyBase::checkAndHandleRecovery() { + using namespace power; + if (recoveryState == RECOVERY_IDLE) { + return AssemblyBase::checkAndHandleRecovery(); + } + if (customRecoveryStates == IDLE) { + switcher.turnOff(); + customRecoveryStates = RecoveryCustomStates::POWER_SWITCHING_OFF; + } + if (customRecoveryStates == POWER_SWITCHING_OFF) { + switcher.doStateMachine(); + if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { + customRecoveryStates = RecoveryCustomStates::POWER_SWITCHING_ON; + switcher.turnOn(); + } + } + if (customRecoveryStates == POWER_SWITCHING_ON) { + switcher.doStateMachine(); + if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { + customRecoveryStates = RecoveryCustomStates::DONE; + } + } + if (customRecoveryStates == DONE) { + bool pendingRecovery = AssemblyBase::checkAndHandleRecovery(); + if (not pendingRecovery) { + customRecoveryStates = RecoveryCustomStates::IDLE; + } + // For a recovery on one side, only do the recovery once + for (auto& child : childrenMap) { + if (healthHelper.healthTable->getHealth(child.first) == HasHealthIF::NEEDS_RECOVERY) { + sendHealthCommand(child.second.commandQueue, HEALTHY); + child.second.healthChanged = false; + } + } + return pendingRecovery; + } + return true; +} diff --git a/mission/system/SharedPowerAssemblyBase.h b/mission/system/SharedPowerAssemblyBase.h new file mode 100644 index 00000000..c269a52f --- /dev/null +++ b/mission/system/SharedPowerAssemblyBase.h @@ -0,0 +1,27 @@ +#ifndef MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_ +#define MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_ + +#include +#include +#include + +/** + * Base class which contains common functions for assemblies where the power line is shared + * among the devices in the assembly. + */ +class SharedPowerAssemblyBase : public AssemblyBase { + public: + SharedPowerAssemblyBase(object_id_t objectId, PowerSwitchIF* pwrSwitcher, + power::Switch_t switchId, uint16_t cmdQueueDepth = 8); + + protected: + PowerSwitcher switcher; + power::RecoveryCustomStates customRecoveryStates = power::RecoveryCustomStates::IDLE; + + void performChildOperation() override; + void startTransition(Mode_t mode, Submode_t submode) override; + void handleModeReached() override; + virtual bool checkAndHandleRecovery() override; +}; + +#endif /* MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_ */ diff --git a/mission/system/acs/DualLaneAssemblyBase.h b/mission/system/acs/DualLaneAssemblyBase.h index 40d9aefc..a30bad5b 100644 --- a/mission/system/acs/DualLaneAssemblyBase.h +++ b/mission/system/acs/DualLaneAssemblyBase.h @@ -39,12 +39,7 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF { SideSwitchState sideSwitchState = SideSwitchState::NONE; duallane::Submodes targetSubmodeForSideSwitch = duallane::Submodes::B_SIDE; - enum RecoveryCustomStates { - IDLE, - POWER_SWITCHING_OFF, - POWER_SWITCHING_ON, - DONE - } customRecoveryStates = RecoveryCustomStates::IDLE; + power::RecoveryCustomStates customRecoveryStates = power::RecoveryCustomStates::IDLE; MessageQueueIF* eventQueue = nullptr; diff --git a/mission/system/acs/RwAssembly.cpp b/mission/system/acs/RwAssembly.cpp index eacd8d0d..68b7c2da 100644 --- a/mission/system/acs/RwAssembly.cpp +++ b/mission/system/acs/RwAssembly.cpp @@ -1,8 +1,8 @@ #include "RwAssembly.h" -RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher, +RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switchId, RwHelper helper) - : AssemblyBase(objectId), helper(helper), switcher(pwrSwitcher, switcher) { + : SharedPowerAssemblyBase(objectId, pwrSwitcher, switchId), helper(helper) { ModeListEntry entry; for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) { entry.setObject(helper.rwIds[idx]); @@ -12,26 +12,8 @@ RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power:: } } -void RwAssembly::performChildOperation() { - auto state = switcher.getState(); - if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) { - AssemblyBase::performChildOperation(); - return; - } - switcher.doStateMachine(); - if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { - // Indicator that a transition to off is finished - AssemblyBase::handleModeReached(); - } else if (state == PowerSwitcher::WAIT_ON and - switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { - // Indicator that mode commanding can be performed now - AssemblyBase::startTransition(targetMode, targetSubmode); - } -} - ReturnValue_t RwAssembly::commandChildren(Mode_t mode, Submode_t submode) { ReturnValue_t result = returnvalue::OK; - modeTransitionFailedSwitch = true; // Initialize the mode table to ensure all devices are in a defined state for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) { modeTable[idx].setMode(MODE_OFF); @@ -76,36 +58,6 @@ ReturnValue_t RwAssembly::isModeCombinationValid(Mode_t mode, Submode_t submode) return HasModesIF::INVALID_MODE; } -void RwAssembly::startTransition(Mode_t mode, Submode_t submode) { - if (mode != MODE_OFF) { - switcher.turnOn(true); - switcher.doStateMachine(); - if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { - AssemblyBase::startTransition(mode, submode); - } else { - // Need to wait with mode commanding until power switcher is done - targetMode = mode; - targetSubmode = submode; - } - } else { - // Perform regular mode commanding first - AssemblyBase::startTransition(mode, submode); - } -} - -void RwAssembly::handleModeReached() { - if (targetMode == MODE_OFF) { - switcher.turnOff(true); - switcher.doStateMachine(); - // Need to wait with call to AssemblyBase::handleModeReached until power switcher is done - if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { - AssemblyBase::handleModeReached(); - } - } else { - AssemblyBase::handleModeReached(); - } -} - ReturnValue_t RwAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) { ReturnValue_t result = returnvalue::OK; object_id_t objId = 0; diff --git a/mission/system/acs/RwAssembly.h b/mission/system/acs/RwAssembly.h index 540e37cc..178595b4 100644 --- a/mission/system/acs/RwAssembly.h +++ b/mission/system/acs/RwAssembly.h @@ -1,8 +1,8 @@ #ifndef MISSION_SYSTEM_RWASS_H_ #define MISSION_SYSTEM_RWASS_H_ -#include #include +#include struct RwHelper { RwHelper(std::array rwIds) : rwIds(rwIds) {} @@ -10,17 +10,15 @@ struct RwHelper { std::array rwIds = {}; }; -class RwAssembly : public AssemblyBase { +class RwAssembly : public SharedPowerAssemblyBase { public: - RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher, + RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switchId, RwHelper helper); private: static constexpr uint8_t NUMBER_RWS = 4; RwHelper helper; - PowerSwitcher switcher; bool warningSwitch = true; - bool modeTransitionFailedSwitch = true; FixedArrayList modeTable; ReturnValue_t initialize() override; @@ -35,12 +33,9 @@ class RwAssembly : public AssemblyBase { bool isUseable(object_id_t object, Mode_t mode); // AssemblyBase implementation - void performChildOperation() override; ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override; ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override; - void startTransition(Mode_t mode, Submode_t submode) override; - void handleModeReached() override; }; #endif /* MISSION_SYSTEM_RWASS_H_ */ diff --git a/mission/system/fdir/RtdFdir.cpp b/mission/system/fdir/RtdFdir.cpp index 008dc405..24ebc2a2 100644 --- a/mission/system/fdir/RtdFdir.cpp +++ b/mission/system/fdir/RtdFdir.cpp @@ -3,4 +3,4 @@ #include "eive/objects.h" RtdFdir::RtdFdir(object_id_t sensorId) - : DeviceHandlerFailureIsolation(sensorId, objects::TCS_BOARD_ASS) {} + : DeviceHandlerFailureIsolation(sensorId, objects::NO_OBJECT) {} diff --git a/mission/system/objects/TcsBoardAssembly.cpp b/mission/system/objects/TcsBoardAssembly.cpp index b32a00a9..2a5a3e7b 100644 --- a/mission/system/objects/TcsBoardAssembly.cpp +++ b/mission/system/objects/TcsBoardAssembly.cpp @@ -4,9 +4,11 @@ #include TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, - power::Switch_t theSwitch, TcsBoardHelper helper) - : AssemblyBase(objectId, 24), switcher(pwrSwitcher, theSwitch), helper(helper) { - eventQueue = QueueFactory::instance()->createMessageQueue(24); + power::Switch_t theSwitch, TcsBoardHelper helper, + std::atomic_bool& tcsShortlyUnavailable) + : SharedPowerAssemblyBase(objectId, pwrSwitcher, theSwitch, 16), + helper(helper), + tcsShortlyUnavailable(tcsShortlyUnavailable) { ModeListEntry entry; for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { entry.setObject(helper.rtdInfos[idx].first); @@ -16,23 +18,6 @@ TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitc } } -void TcsBoardAssembly::performChildOperation() { - auto state = switcher.getState(); - if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) { - AssemblyBase::performChildOperation(); - return; - } - switcher.doStateMachine(); - if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { - // Indicator that a transition to off is finished - AssemblyBase::handleModeReached(); - } else if (state == PowerSwitcher::WAIT_ON and - switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { - // Indicator that mode commanding can be performed now - AssemblyBase::startTransition(targetMode, targetSubmode); - } -} - ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) { ReturnValue_t result = returnvalue::OK; // Initialize the mode table to ensure all devices are in a defined state @@ -50,6 +35,8 @@ ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) { result = handleNormalOrOnModeCmd(mode, submode); } + } else { + tcsShortlyUnavailable = true; } HybridIterator tableIter(modeTable.begin(), modeTable.end()); executeTable(tableIter); @@ -94,25 +81,6 @@ ReturnValue_t TcsBoardAssembly::isModeCombinationValid(Mode_t mode, Submode_t su return HasModesIF::INVALID_MODE; } -ReturnValue_t TcsBoardAssembly::initialize() { return AssemblyBase::initialize(); } - -void TcsBoardAssembly::startTransition(Mode_t mode, Submode_t submode) { - if (mode != MODE_OFF) { - switcher.turnOn(true); - switcher.doStateMachine(); - if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) { - AssemblyBase::startTransition(mode, submode); - } else { - // Need to wait with mode commanding until power switcher is done - targetMode = mode; - targetSubmode = submode; - } - } else { - // Perform regular mode commanding first - AssemblyBase::startTransition(mode, submode); - } -} - ReturnValue_t TcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) { ReturnValue_t result = returnvalue::OK; bool needsSecondStep = false; @@ -169,21 +137,6 @@ bool TcsBoardAssembly::isUseable(object_id_t object, Mode_t mode) { return false; } -MessageQueueId_t TcsBoardAssembly::getEventReceptionQueue() { return eventQueue->getId(); } - -void TcsBoardAssembly::handleModeReached() { - if (targetMode == MODE_OFF) { - switcher.turnOff(true); - switcher.doStateMachine(); - // Need to wait with call to AssemblyBase::handleModeReached until power switcher is done - if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) { - AssemblyBase::handleModeReached(); - } - } else { - AssemblyBase::handleModeReached(); - } -} - void TcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) { triggerEvent(CHILDREN_LOST_MODE, result); startTransition(mode, submode); @@ -210,6 +163,12 @@ ReturnValue_t TcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode, return status; } +bool TcsBoardAssembly::checkAndHandleRecovery() { + bool recoveryPending = SharedPowerAssemblyBase::checkAndHandleRecovery(); + tcsShortlyUnavailable = recoveryPending; + return recoveryPending; +} + void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) { if (targetMode == MODE_OFF) { AssemblyBase::handleModeTransitionFailed(result); diff --git a/mission/system/objects/TcsBoardAssembly.h b/mission/system/objects/TcsBoardAssembly.h index 3c3fc0d6..da10999c 100644 --- a/mission/system/objects/TcsBoardAssembly.h +++ b/mission/system/objects/TcsBoardAssembly.h @@ -4,6 +4,10 @@ #include #include #include +#include +#include + +#include #include "events/subsystemIdRanges.h" #include "returnvalues/classIds.h" @@ -15,23 +19,20 @@ struct TcsBoardHelper { std::array, 16> rtdInfos = {}; }; -class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF { +class TcsBoardAssembly : public SharedPowerAssemblyBase { public: static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_BOARD_ASS; static constexpr Event CHILDREN_LOST_MODE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher, - TcsBoardHelper helper); - - ReturnValue_t initialize() override; + TcsBoardHelper helper, std::atomic_bool& tcsShortlyUnavailable); private: static constexpr uint8_t NUMBER_RTDS = 16; - PowerSwitcher switcher; bool warningSwitch = true; TcsBoardHelper helper; FixedArrayList modeTable; - MessageQueueIF* eventQueue = nullptr; + std::atomic_bool& tcsShortlyUnavailable; ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode); /** @@ -42,17 +43,12 @@ class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF { */ bool isUseable(object_id_t object, Mode_t mode); - // ConfirmFailureIF implementation - MessageQueueId_t getEventReceptionQueue() override; - // AssemblyBase implementation - void performChildOperation() override; ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override; ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override; - void startTransition(Mode_t mode, Submode_t submode) override; - void handleModeReached() override; ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode); + bool checkAndHandleRecovery() override; // These two overrides prevent a transition of the whole assembly back to off just because // some devices are not working diff --git a/mission/tcs/defs.h b/mission/tcs/defs.h new file mode 100644 index 00000000..df868360 --- /dev/null +++ b/mission/tcs/defs.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace tcs { + +extern std::atomic_bool TCS_BOARD_SHORTLY_UNAVAILABLE; + +} diff --git a/tmtc b/tmtc index 43b530cd..f075d289 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 43b530cdb7dfe6774962bf4b8a880e1c9a6e6580 +Subproject commit f075d28905b42a018b275d8c640cb0fd9d64dc26 diff --git a/unittest/controller/testThermalController.cpp b/unittest/controller/testThermalController.cpp index 623c6d52..dbe86949 100644 --- a/unittest/controller/testThermalController.cpp +++ b/unittest/controller/testThermalController.cpp @@ -15,6 +15,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { const object_id_t THERMAL_CONTROLLER_ID = 0x123; + std::atomic_bool tcsBrdShortlyUnavailable = false; TemperatureSensorInserter::Max31865DummyMap map0; TemperatureSensorInserter::Tmp1075DummyMap map1; @@ -29,7 +30,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { // testEnvironment::initialize(); - ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler); + ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler, tcsBrdShortlyUnavailable); ReturnValue_t result = controller.initialize(); REQUIRE(result == returnvalue::OK);