Merge pull request 'Shared Power Switch Assembly' (#590) from assy_proper_recovery_handling into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #590
This commit is contained in:
Robin Müller 2023-04-12 12:58:48 +02:00
commit d71031f2e4
20 changed files with 202 additions and 150 deletions

View File

@ -26,6 +26,8 @@ will consitute of a breaking change warranting a new major release:
temperature for the all-ones value (0x0fff). temperature for the all-ones value (0x0fff).
- Better reply result handling for the ACS board devices. - Better reply result handling for the ACS board devices.
- ADIS1650X initial timeout handling now performed in device handler. - 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 ## 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. 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 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. 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 ## Changed

View File

@ -40,6 +40,7 @@
#include "mission/system/com/comModeTree.h" #include "mission/system/com/comModeTree.h"
#include "mission/system/tree/payloadModeTree.h" #include "mission/system/tree/payloadModeTree.h"
#include "mission/system/tree/tcsModeTree.h" #include "mission/system/tree/tcsModeTree.h"
#include "mission/tcs/defs.h"
void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) { void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) {
new ComIFDummy(objects::DUMMY_COM_IF); 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, new TemperatureSensorInserter(objects::THERMAL_TEMP_INSERTER, rtdSensorDummies,
tmpSensorDummies); tmpSensorDummies);
TcsBoardAssembly* tcsBoardAssy = ObjectFactory::createTcsBoardAssy(pwrSwitcher); TcsBoardAssembly* tcsBoardAssy =
ObjectFactory::createTcsBoardAssy(pwrSwitcher, tcs::TCS_BOARD_SHORTLY_UNAVAILABLE);
for (auto& rtd : rtdSensorDummies) { for (auto& rtd : rtdSensorDummies) {
rtd.second->connectModeTreeParent(*tcsBoardAssy); rtd.second->connectModeTreeParent(*tcsBoardAssy);
} }

View File

@ -29,6 +29,7 @@
#include "mission/system/acs/acsModeTree.h" #include "mission/system/acs/acsModeTree.h"
#include "mission/system/tree/payloadModeTree.h" #include "mission/system/tree/payloadModeTree.h"
#include "mission/system/tree/tcsModeTree.h" #include "mission/system/tree/tcsModeTree.h"
#include "mission/tcs/defs.h"
void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF, void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF,
PowerSwitchIF& pwrSwitcher, std::string spiDev, PowerSwitchIF& pwrSwitcher, std::string spiDev,
@ -278,7 +279,8 @@ void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF,
std::array<Max31865EiveHandler*, NUM_RTDS> rtds = {}; std::array<Max31865EiveHandler*, NUM_RTDS> rtds = {};
RtdFdir* rtdFdir = nullptr; 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 // Create special low level reader communication interface
new Max31865RtdPolling(objects::SPI_RTD_COM_IF, comIF, gpioComIF); new Max31865RtdPolling(objects::SPI_RTD_COM_IF, comIF, gpioComIF);

View File

@ -21,7 +21,8 @@
#define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_EBAND_UPPER_LIMITS 0
#define LOWER_PLOC_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), : ExtendedControllerBase(objectId),
heaterHandler(heater), heaterHandler(heater),
sensorTemperatures(this), sensorTemperatures(this),
@ -66,7 +67,8 @@ ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater
susSet8(objects::SUS_8_R_LOC_XBYBZB_PT_YB), susSet8(objects::SUS_8_R_LOC_XBYBZB_PT_YB),
susSet9(objects::SUS_9_R_LOC_XBYBZB_PT_YF), susSet9(objects::SUS_9_R_LOC_XBYBZB_PT_YF),
susSet10(objects::SUS_10_N_LOC_XMYBZF_PT_ZF), 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(); resetSensorsArray();
} }
@ -134,10 +136,12 @@ void ThermalController::performControlOperation() {
} }
} }
{ if (not tcsBrdShortlyUnavailable) {
PoolReadGuard pg(&sensorTemperatures); {
if (pg.getReadResult() == returnvalue::OK) { PoolReadGuard pg(&sensorTemperatures);
copySensors(); if (pg.getReadResult() == returnvalue::OK) {
copySensors();
}
} }
} }
{ {
@ -182,7 +186,7 @@ void ThermalController::performControlOperation() {
} }
setMode(MODE_OFF); setMode(MODE_OFF);
} }
} else if (mode != MODE_OFF) { } else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) {
performThermalModuleCtrl(heaterSwitchStateArray); performThermalModuleCtrl(heaterSwitchStateArray);
} }
cycles++; cycles++;

View File

@ -22,6 +22,7 @@
#include <mission/tcs/Tmp1075Definitions.h> #include <mission/tcs/Tmp1075Definitions.h>
#include <mission/utility/trace.h> #include <mission/utility/trace.h>
#include <atomic>
#include <list> #include <list>
/** /**
@ -94,7 +95,8 @@ class ThermalController : public ExtendedControllerBase {
static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80;
static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160; 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; ReturnValue_t initialize() override;
@ -181,6 +183,10 @@ class ThermalController : public ExtendedControllerBase {
susMax1227::SusDataset susSet10; susMax1227::SusDataset susSet10;
susMax1227::SusDataset susSet11; 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<float> tempQ7s = lp_var_t<float>(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE); lp_var_t<float> tempQ7s = lp_var_t<float>(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE);
lp_var_t<int16_t> battTemp1 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1); lp_var_t<int16_t> battTemp1 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1);
lp_var_t<int16_t> battTemp2 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2); lp_var_t<int16_t> battTemp2 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2);

View File

@ -48,6 +48,7 @@
#include "mission/system/acs/RwAssembly.h" #include "mission/system/acs/RwAssembly.h"
#include "mission/system/acs/acsModeTree.h" #include "mission/system/acs/acsModeTree.h"
#include "mission/system/tree/tcsModeTree.h" #include "mission/system/tree/tcsModeTree.h"
#include "mission/tcs/defs.h"
#include "mission/tmtc/tmFilters.h" #include "mission/tmtc/tmFilters.h"
#include "objects/systemObjectList.h" #include "objects/systemObjectList.h"
#include "tmtc/pusIds.h" #include "tmtc/pusIds.h"
@ -90,6 +91,8 @@ EiveFaultHandler EIVE_FAULT_HANDLER;
} // namespace cfdp } // namespace cfdp
std::atomic_bool tcs::TCS_BOARD_SHORTLY_UNAVAILABLE = false;
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel, void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel,
CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan, CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan,
StorageManagerIF** ipcStore, StorageManagerIF** tmStore, StorageManagerIF** ipcStore, StorageManagerIF** tmStore,
@ -300,7 +303,8 @@ void ObjectFactory::createGenericHeaterComponents(GpioIF& gpioIF, PowerSwitchIF&
} }
void ObjectFactory::createThermalController(HeaterHandler& heaterHandler) { 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); tcsCtrl->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
} }
void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch, void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch,
@ -366,10 +370,12 @@ void ObjectFactory::createAcsBoardAssy(PowerSwitchIF& pwrSwitcher,
acsAss->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM); acsAss->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
} }
TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher) { TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher,
std::atomic_bool& tcsShortlyUnavailable) {
TcsBoardHelper helper(RTD_INFOS); TcsBoardHelper helper(RTD_INFOS);
auto* tcsBoardAss = new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher, auto* tcsBoardAss =
power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper); new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher,
power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper, tcsShortlyUnavailable);
tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM); tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
return tcsBoardAss; return tcsBoardAss;
} }

View File

@ -55,7 +55,8 @@ void createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch,
void createSusAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 12> suses); void createSusAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 12> suses);
void createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 8> assemblyDhbs, void createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 8> assemblyDhbs,
ExtendedControllerBase* gpsCtrl, GpioIF* gpioComIF); ExtendedControllerBase* gpsCtrl, GpioIF* gpioComIF);
TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher); TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher,
std::atomic_bool& tcsShortlyUnavailable);
} // namespace ObjectFactory } // namespace ObjectFactory

View File

@ -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 States { IDLE, SWITCHING_POWER, CHECKING_POWER, MODE_COMMANDING };
enum class OpCodes { NONE, TO_OFF_DONE, TO_NOT_OFF_DONE, TIMEOUT_OCCURED }; 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 power
namespace duallane { namespace duallane {

View File

@ -6,5 +6,6 @@ add_subdirectory(fdir)
add_subdirectory(power) add_subdirectory(power)
target_sources( target_sources(
${LIB_EIVE_MISSION} PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp ${LIB_EIVE_MISSION}
EiveSystem.cpp treeUtil.cpp) PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp EiveSystem.cpp
treeUtil.cpp SharedPowerAssemblyBase.cpp)

View File

@ -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;
}

View File

@ -0,0 +1,27 @@
#ifndef MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_
#define MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_
#include <fsfw/devicehandlers/AssemblyBase.h>
#include <fsfw/power/PowerSwitcher.h>
#include <mission/power/defs.h>
/**
* 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_ */

View File

@ -39,12 +39,7 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF {
SideSwitchState sideSwitchState = SideSwitchState::NONE; SideSwitchState sideSwitchState = SideSwitchState::NONE;
duallane::Submodes targetSubmodeForSideSwitch = duallane::Submodes::B_SIDE; duallane::Submodes targetSubmodeForSideSwitch = duallane::Submodes::B_SIDE;
enum RecoveryCustomStates { power::RecoveryCustomStates customRecoveryStates = power::RecoveryCustomStates::IDLE;
IDLE,
POWER_SWITCHING_OFF,
POWER_SWITCHING_ON,
DONE
} customRecoveryStates = RecoveryCustomStates::IDLE;
MessageQueueIF* eventQueue = nullptr; MessageQueueIF* eventQueue = nullptr;

View File

@ -1,8 +1,8 @@
#include "RwAssembly.h" #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) RwHelper helper)
: AssemblyBase(objectId), helper(helper), switcher(pwrSwitcher, switcher) { : SharedPowerAssemblyBase(objectId, pwrSwitcher, switchId), helper(helper) {
ModeListEntry entry; ModeListEntry entry;
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) { for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
entry.setObject(helper.rwIds[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 RwAssembly::commandChildren(Mode_t mode, Submode_t submode) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
modeTransitionFailedSwitch = true;
// Initialize the mode table to ensure all devices are in a defined state // Initialize the mode table to ensure all devices are in a defined state
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) { for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
modeTable[idx].setMode(MODE_OFF); modeTable[idx].setMode(MODE_OFF);
@ -76,36 +58,6 @@ ReturnValue_t RwAssembly::isModeCombinationValid(Mode_t mode, Submode_t submode)
return HasModesIF::INVALID_MODE; 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 RwAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
object_id_t objId = 0; object_id_t objId = 0;

View File

@ -1,8 +1,8 @@
#ifndef MISSION_SYSTEM_RWASS_H_ #ifndef MISSION_SYSTEM_RWASS_H_
#define MISSION_SYSTEM_RWASS_H_ #define MISSION_SYSTEM_RWASS_H_
#include <fsfw/devicehandlers/AssemblyBase.h>
#include <fsfw/power/PowerSwitcher.h> #include <fsfw/power/PowerSwitcher.h>
#include <mission/system/SharedPowerAssemblyBase.h>
struct RwHelper { struct RwHelper {
RwHelper(std::array<object_id_t, 4> rwIds) : rwIds(rwIds) {} RwHelper(std::array<object_id_t, 4> rwIds) : rwIds(rwIds) {}
@ -10,17 +10,15 @@ struct RwHelper {
std::array<object_id_t, 4> rwIds = {}; std::array<object_id_t, 4> rwIds = {};
}; };
class RwAssembly : public AssemblyBase { class RwAssembly : public SharedPowerAssemblyBase {
public: 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); RwHelper helper);
private: private:
static constexpr uint8_t NUMBER_RWS = 4; static constexpr uint8_t NUMBER_RWS = 4;
RwHelper helper; RwHelper helper;
PowerSwitcher switcher;
bool warningSwitch = true; bool warningSwitch = true;
bool modeTransitionFailedSwitch = true;
FixedArrayList<ModeListEntry, NUMBER_RWS> modeTable; FixedArrayList<ModeListEntry, NUMBER_RWS> modeTable;
ReturnValue_t initialize() override; ReturnValue_t initialize() override;
@ -35,12 +33,9 @@ class RwAssembly : public AssemblyBase {
bool isUseable(object_id_t object, Mode_t mode); bool isUseable(object_id_t object, Mode_t mode);
// AssemblyBase implementation // AssemblyBase implementation
void performChildOperation() override;
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override; ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) 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_ */ #endif /* MISSION_SYSTEM_RWASS_H_ */

View File

@ -3,4 +3,4 @@
#include "eive/objects.h" #include "eive/objects.h"
RtdFdir::RtdFdir(object_id_t sensorId) RtdFdir::RtdFdir(object_id_t sensorId)
: DeviceHandlerFailureIsolation(sensorId, objects::TCS_BOARD_ASS) {} : DeviceHandlerFailureIsolation(sensorId, objects::NO_OBJECT) {}

View File

@ -4,9 +4,11 @@
#include <fsfw/ipc/QueueFactory.h> #include <fsfw/ipc/QueueFactory.h>
TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
power::Switch_t theSwitch, TcsBoardHelper helper) power::Switch_t theSwitch, TcsBoardHelper helper,
: AssemblyBase(objectId, 24), switcher(pwrSwitcher, theSwitch), helper(helper) { std::atomic_bool& tcsShortlyUnavailable)
eventQueue = QueueFactory::instance()->createMessageQueue(24); : SharedPowerAssemblyBase(objectId, pwrSwitcher, theSwitch, 16),
helper(helper),
tcsShortlyUnavailable(tcsShortlyUnavailable) {
ModeListEntry entry; ModeListEntry entry;
for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) {
entry.setObject(helper.rtdInfos[idx].first); 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 TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
// Initialize the mode table to ensure all devices are in a defined state // 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) { if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) {
result = handleNormalOrOnModeCmd(mode, submode); result = handleNormalOrOnModeCmd(mode, submode);
} }
} else {
tcsShortlyUnavailable = true;
} }
HybridIterator<ModeListEntry> tableIter(modeTable.begin(), modeTable.end()); HybridIterator<ModeListEntry> tableIter(modeTable.begin(), modeTable.end());
executeTable(tableIter); executeTable(tableIter);
@ -94,25 +81,6 @@ ReturnValue_t TcsBoardAssembly::isModeCombinationValid(Mode_t mode, Submode_t su
return HasModesIF::INVALID_MODE; 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 TcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
bool needsSecondStep = false; bool needsSecondStep = false;
@ -169,21 +137,6 @@ bool TcsBoardAssembly::isUseable(object_id_t object, Mode_t mode) {
return false; 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) { void TcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) {
triggerEvent(CHILDREN_LOST_MODE, result); triggerEvent(CHILDREN_LOST_MODE, result);
startTransition(mode, submode); startTransition(mode, submode);
@ -210,6 +163,12 @@ ReturnValue_t TcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode,
return status; return status;
} }
bool TcsBoardAssembly::checkAndHandleRecovery() {
bool recoveryPending = SharedPowerAssemblyBase::checkAndHandleRecovery();
tcsShortlyUnavailable = recoveryPending;
return recoveryPending;
}
void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) { void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) {
if (targetMode == MODE_OFF) { if (targetMode == MODE_OFF) {
AssemblyBase::handleModeTransitionFailed(result); AssemblyBase::handleModeTransitionFailed(result);

View File

@ -4,6 +4,10 @@
#include <fsfw/container/FixedArrayList.h> #include <fsfw/container/FixedArrayList.h>
#include <fsfw/devicehandlers/AssemblyBase.h> #include <fsfw/devicehandlers/AssemblyBase.h>
#include <fsfw/power/PowerSwitcher.h> #include <fsfw/power/PowerSwitcher.h>
#include <mission/power/defs.h>
#include <mission/system/SharedPowerAssemblyBase.h>
#include <atomic>
#include "events/subsystemIdRanges.h" #include "events/subsystemIdRanges.h"
#include "returnvalues/classIds.h" #include "returnvalues/classIds.h"
@ -15,23 +19,20 @@ struct TcsBoardHelper {
std::array<std::pair<object_id_t, std::string>, 16> rtdInfos = {}; std::array<std::pair<object_id_t, std::string>, 16> rtdInfos = {};
}; };
class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF { class TcsBoardAssembly : public SharedPowerAssemblyBase {
public: public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_BOARD_ASS; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_BOARD_ASS;
static constexpr Event CHILDREN_LOST_MODE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); static constexpr Event CHILDREN_LOST_MODE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher, TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher,
TcsBoardHelper helper); TcsBoardHelper helper, std::atomic_bool& tcsShortlyUnavailable);
ReturnValue_t initialize() override;
private: private:
static constexpr uint8_t NUMBER_RTDS = 16; static constexpr uint8_t NUMBER_RTDS = 16;
PowerSwitcher switcher;
bool warningSwitch = true; bool warningSwitch = true;
TcsBoardHelper helper; TcsBoardHelper helper;
FixedArrayList<ModeListEntry, NUMBER_RTDS> modeTable; FixedArrayList<ModeListEntry, NUMBER_RTDS> modeTable;
MessageQueueIF* eventQueue = nullptr; std::atomic_bool& tcsShortlyUnavailable;
ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode); 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); bool isUseable(object_id_t object, Mode_t mode);
// ConfirmFailureIF implementation
MessageQueueId_t getEventReceptionQueue() override;
// AssemblyBase implementation // AssemblyBase implementation
void performChildOperation() override;
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override; ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override; ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) 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); 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 // These two overrides prevent a transition of the whole assembly back to off just because
// some devices are not working // some devices are not working

9
mission/tcs/defs.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <atomic>
namespace tcs {
extern std::atomic_bool TCS_BOARD_SHORTLY_UNAVAILABLE;
}

2
tmtc

@ -1 +1 @@
Subproject commit 43b530cdb7dfe6774962bf4b8a880e1c9a6e6580 Subproject commit f075d28905b42a018b275d8c640cb0fd9d64dc26

View File

@ -15,6 +15,7 @@
TEST_CASE("Thermal Controller", "[ThermalController]") { TEST_CASE("Thermal Controller", "[ThermalController]") {
const object_id_t THERMAL_CONTROLLER_ID = 0x123; const object_id_t THERMAL_CONTROLLER_ID = 0x123;
std::atomic_bool tcsBrdShortlyUnavailable = false;
TemperatureSensorInserter::Max31865DummyMap map0; TemperatureSensorInserter::Max31865DummyMap map0;
TemperatureSensorInserter::Tmp1075DummyMap map1; TemperatureSensorInserter::Tmp1075DummyMap map1;
@ -29,7 +30,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") {
// testEnvironment::initialize(); // testEnvironment::initialize();
ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler); ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler, tcsBrdShortlyUnavailable);
ReturnValue_t result = controller.initialize(); ReturnValue_t result = controller.initialize();
REQUIRE(result == returnvalue::OK); REQUIRE(result == returnvalue::OK);