diff --git a/src/fsfw/devicehandlers/AssemblyBase.cpp b/src/fsfw/devicehandlers/AssemblyBase.cpp index c29022e5..414098ad 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.cpp +++ b/src/fsfw/devicehandlers/AssemblyBase.cpp @@ -26,11 +26,7 @@ void AssemblyBase::performChildOperation() { void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) { doStartTransition(mode, submode); - if (modeHelper.isForced()) { - triggerEvent(FORCING_MODE, mode, submode); - } else { - triggerEvent(CHANGING_MODE, mode, submode); - } + triggerModeHelperEvents(mode, submode); } void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) { @@ -77,9 +73,10 @@ bool AssemblyBase::handleChildrenChangedHealth() { } HealthState healthState = healthHelper.healthTable->getHealth(iter->first); if (healthState == HasHealthIF::NEEDS_RECOVERY) { - triggerEvent(TRYING_RECOVERY); + triggerEvent(TRYING_RECOVERY, iter->first, 0); recoveryState = RECOVERY_STARTED; recoveringDevice = iter; + // The user needs to take care of commanding the children off in commandChildren doStartTransition(targetMode, targetSubmode); } else { triggerEvent(CHILD_CHANGED_HEALTH); @@ -228,6 +225,9 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) { bool AssemblyBase::checkAndHandleRecovery() { switch (recoveryState) { case RECOVERY_STARTED: + // The recovery was already start in #handleChildrenChangedHealth and we just need + // to wait for an off time period. + // TODO: make time period configurable recoveryState = RECOVERY_WAIT; recoveryOffTimer.resetTimer(); return true; @@ -266,3 +266,11 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal modeHelper.setForced(true); sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL); } + +void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) { + if (modeHelper.isForced()) { + triggerEvent(FORCING_MODE, mode, submode); + } else { + triggerEvent(CHANGING_MODE, mode, submode); + } +} diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h index f6192533..a6e6e3db 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.h +++ b/src/fsfw/devicehandlers/AssemblyBase.h @@ -12,7 +12,8 @@ * Documentation: Dissertation Baetz p.156, 157. * * This class reduces the complexity of controller components which would - * otherwise be needed for the handling of redundant devices. + * otherwise be needed for the handling of redundant devices. However, it can also be used to + * manage the mode keeping and recovery of non-redundant devices * * The template class monitors mode and health state of its children * and checks availability of devices on every detected change. @@ -26,11 +27,9 @@ * * Important: * - * The implementation must call registerChild(object_id_t child) - * for all commanded children during initialization. + * The implementation must call #registerChild for all commanded children during initialization. * The implementation must call the initialization function of the base class. * (This will call the function in SubsystemBase) - * */ class AssemblyBase : public SubsystemBase { public: @@ -47,9 +46,10 @@ class AssemblyBase : public SubsystemBase { protected: /** - * Command children to reach [mode,submode] combination - * Can be done by setting #commandsOutstanding correctly, - * or using executeTable() + * Command children to reach [mode,submode] combination. Can be done by setting + * #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery, + * the user needs to ensure that the target devices are healthy. If a device is not healthy, + * a recovery might be on-going and the device needs to be commanded to off first. * @param mode * @param submode * @return @@ -162,6 +162,12 @@ class AssemblyBase : public SubsystemBase { ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode); + /** + * Calls #doStartTransition and triggers an informative event as well that the mode will + * change + * @param mode + * @param submode + */ virtual void startTransition(Mode_t mode, Submode_t submode); /** @@ -190,7 +196,7 @@ class AssemblyBase : public SubsystemBase { * Manages recovery of a device * @return true if recovery is still ongoing, false else. */ - bool checkAndHandleRecovery(); + virtual bool checkAndHandleRecovery(); /** * Helper method to overwrite health state of one of the children. @@ -198,6 +204,8 @@ class AssemblyBase : public SubsystemBase { * @param objectId Must be a registered child. */ void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth); + + void triggerModeHelperEvents(Mode_t mode, Submode_t submode); }; #endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 03f8da54..18f8a2f7 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -49,9 +49,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", HasReturnvaluesIF::RETURN_FAILED, "Invalid cookie"); } - if (this->fdirInstance == nullptr) { - this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId); - } } void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) { @@ -127,6 +124,17 @@ ReturnValue_t DeviceHandlerBase::initialize() { if (result != RETURN_OK) { return result; } + if (this->fdirInstance == nullptr) { + this->fdirInstance = new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId); + } + + if(this->parent != objects::NO_OBJECT) { + HasModesIF* modeIF = ObjectManager::instance()->get(this->parent); + HasHealthIF* healthIF = ObjectManager::instance()->get(this->parent); + if(modeIF != nullptr and healthIF != nullptr) { + setParentQueue(modeIF->getCommandQueue()); + } + } communicationInterface = ObjectManager::instance()->get(deviceCommunicationId); @@ -1494,3 +1502,9 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI } return commandIter->second.sendReplyTo; } + +void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; } + +void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; } + +void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) { this->powerSwitcher = switcher; } diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index bf6900d9..a8de34eb 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -103,6 +103,9 @@ class DeviceHandlerBase : public DeviceHandlerIF, DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie, FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20); + void setCustomFdir(FailureIsolationBase* fdir); + void setParent(object_id_t parent); + void setPowerSwitcher(PowerSwitchIF* switcher); void setHkDestination(object_id_t hkDestination); /** @@ -824,6 +827,7 @@ class DeviceHandlerBase : public DeviceHandlerIF, /** Pointer to the used FDIR instance. If not provided by child, * default class is instantiated. */ FailureIsolationBase *fdirInstance; + object_id_t parent = objects::NO_OBJECT; //! To correctly delete the default instance. bool defaultFDIRUsed; diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp index 5d04588f..c17cf624 100644 --- a/src/fsfw/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -52,11 +52,12 @@ ReturnValue_t FailureIsolationBase::initialize() { ObjectManager::instance()->get(faultTreeParent); if (parentIF == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "FailureIsolationBase::intialize: Parent object" - << "invalid." << std::endl; -#endif -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl; + sif::error << "FailureIsolationBase::intialize: Parent object " + << "invalid" << std::endl; + sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl; +#else + sif::printError("FailureIsolationBase::intialize: Parent object invalid\n"); + sif::printError("Make sure it implements ConfirmsFailuresIF\n"); #endif return ObjectManagerIF::CHILD_INIT_FAILED; return RETURN_FAILED; diff --git a/src/fsfw/power/PowerSwitchIF.h b/src/fsfw/power/PowerSwitchIF.h index a31d8971..b2c0cb9b 100644 --- a/src/fsfw/power/PowerSwitchIF.h +++ b/src/fsfw/power/PowerSwitchIF.h @@ -1,6 +1,7 @@ #ifndef FSFW_POWER_POWERSWITCHIF_H_ #define FSFW_POWER_POWERSWITCHIF_H_ +#include "definitions.h" #include "../events/Event.h" #include "../returnvalues/HasReturnvaluesIF.h" /** @@ -37,7 +38,7 @@ class PowerSwitchIF : public HasReturnvaluesIF { * @param switchNr * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON */ - virtual void sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) const = 0; + virtual void sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) const = 0; /** * Sends a command to the Power Unit to enable a certain fuse. */ @@ -51,7 +52,7 @@ class PowerSwitchIF : public HasReturnvaluesIF { * - @c SWITCH_OFF if the specified switch is off. * - @c RETURN_FAILED if an error occured */ - virtual ReturnValue_t getSwitchState(uint8_t switchNr) const = 0; + virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0; /** * get state of a fuse. * @param fuseNr diff --git a/src/fsfw/power/PowerSwitcher.cpp b/src/fsfw/power/PowerSwitcher.cpp index 0a3f8521..83679772 100644 --- a/src/fsfw/power/PowerSwitcher.cpp +++ b/src/fsfw/power/PowerSwitcher.cpp @@ -1,19 +1,12 @@ +#include "definitions.h" #include "fsfw/power/PowerSwitcher.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" -PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2, - PowerSwitcher::State_t setStartState) - : state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {} - -ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) { - power = ObjectManager::instance()->get(powerSwitchId); - if (power == nullptr) { - return HasReturnvaluesIF::RETURN_FAILED; - } - return HasReturnvaluesIF::RETURN_OK; -} +PowerSwitcher::PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1, + power::Switch_t setSwitch2, PowerSwitcher::State_t setStartState) + : power(switcher), state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2) {} ReturnValue_t PowerSwitcher::getStateOfSwitches() { SwitchReturn_t result = howManySwitches(); @@ -52,18 +45,37 @@ void PowerSwitcher::commandSwitches(ReturnValue_t onOff) { return; } -void PowerSwitcher::turnOn() { +void PowerSwitcher::turnOn(bool checkCurrentState) { + if(checkCurrentState) { + if(getStateOfSwitches() == PowerSwitchIF::SWITCH_ON) { + state = SWITCH_IS_ON; + return; + } + } commandSwitches(PowerSwitchIF::SWITCH_ON); state = WAIT_ON; } -void PowerSwitcher::turnOff() { +void PowerSwitcher::turnOff(bool checkCurrentState) { + if(checkCurrentState) { + if(getStateOfSwitches() == PowerSwitchIF::SWITCH_OFF) { + state = SWITCH_IS_OFF; + return; + } + } commandSwitches(PowerSwitchIF::SWITCH_OFF); state = WAIT_OFF; } +bool PowerSwitcher::active() { + if(state == WAIT_OFF or state == WAIT_ON) { + return true; + } + return false; +} + PowerSwitcher::SwitchReturn_t PowerSwitcher::howManySwitches() { - if (secondSwitch == NO_SWITCH) { + if (secondSwitch == power::NO_SWITCH) { return ONE_SWITCH; } else { return TWO_SWITCHES; diff --git a/src/fsfw/power/PowerSwitcher.h b/src/fsfw/power/PowerSwitcher.h index c72c241d..853bbb40 100644 --- a/src/fsfw/power/PowerSwitcher.h +++ b/src/fsfw/power/PowerSwitcher.h @@ -14,28 +14,28 @@ class PowerSwitcher : public HasReturnvaluesIF { SWITCH_IS_OFF, SWITCH_IS_ON, }; - State_t state; + static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); - PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, + PowerSwitcher(PowerSwitchIF* switcher, uint8_t setSwitch1, uint8_t setSwitch2 = power::NO_SWITCH, State_t setStartState = SWITCH_IS_OFF); - ReturnValue_t initialize(object_id_t powerSwitchId); - void turnOn(); - void turnOff(); + void turnOn(bool checkCurrentState = true); + void turnOff(bool checkCurrentState = true); + bool active(); void doStateMachine(); State_t getState(); ReturnValue_t checkSwitchState(); uint32_t getSwitchDelay(); - uint8_t getFirstSwitch() const; - uint8_t getSecondSwitch() const; + power::Switch_t getFirstSwitch() const; + power::Switch_t getSecondSwitch() const; private: - uint8_t firstSwitch; - uint8_t secondSwitch; PowerSwitchIF* power = nullptr; + State_t state; + power::Switch_t firstSwitch = power::NO_SWITCH; + power::Switch_t secondSwitch = power::NO_SWITCH; - static const uint8_t NO_SWITCH = 0xFF; enum SwitchReturn_t { ONE_SWITCH = 1, TWO_SWITCHES = 2 }; ReturnValue_t getStateOfSwitches(); void commandSwitches(ReturnValue_t onOff); diff --git a/src/fsfw/power/definitions.h b/src/fsfw/power/definitions.h new file mode 100644 index 00000000..1e4fe296 --- /dev/null +++ b/src/fsfw/power/definitions.h @@ -0,0 +1,13 @@ +#ifndef FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ +#define FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ + +#include + +namespace power { + +using Switch_t = uint8_t; +static constexpr Switch_t NO_SWITCH = 0xFF; + +} + +#endif /* FSFW_SRC_FSFW_POWER_DEFINITIONS_H_ */ diff --git a/src/fsfw/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h index 2c78c8cd..953bb682 100644 --- a/src/fsfw/subsystem/Subsystem.h +++ b/src/fsfw/subsystem/Subsystem.h @@ -12,8 +12,12 @@ #include "modes/ModeDefinitions.h" /** - * @brief TODO: documentation missing + * @brief This class extends the SubsystemBase to perform the management of mode tables + * and mode sequences * @details + * This class is able to use mode tables and sequences to command all its children into the + * right mode. Fallback sequences can be used to handle failed transitions or have a fallback + * in case a component can't keep its current mode. */ class Subsystem : public SubsystemBase, public HasModeSequenceIF { public: diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 8cfd5be0..0853ed6e 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -15,7 +15,14 @@ /** * @defgroup subsystems Subsystem Objects - * Contains all Subsystem and Assemblies + * All Subsystem and Assemblies can derive from this class. It contains helper classes to + * perform mode and health handling, which allows OBSW developers to build a mode tree for + * the whole satellite. + * + * Aside from setting up a mode tree and being able to executing mode tables, this class does not + * provide an implementation on what to do with the features. To build a mode tree, helper classes + * like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base + * class. */ class SubsystemBase : public SystemObject, public HasModesIF, @@ -96,6 +103,7 @@ class SubsystemBase : public SystemObject, Submode_t targetSubmode); /** + * This function takes care of sending all according mode commands specified inside a mode table. * We need to know the target Submode, as children are able to inherit the submode * Still, we have a default for all child implementations which do not use submode inheritance */ @@ -123,11 +131,11 @@ class SubsystemBase : public SystemObject, virtual void performChildOperation() = 0; virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, - uint32_t *msToReachTheMode) = 0; + uint32_t *msToReachTheMode) override = 0; - virtual void startTransition(Mode_t mode, Submode_t submode) = 0; + virtual void startTransition(Mode_t mode, Submode_t submode) override = 0; - virtual void getMode(Mode_t *mode, Submode_t *submode); + virtual void getMode(Mode_t *mode, Submode_t *submode) override; virtual void setToExternalControl();