From 1742371c1429dd664963fb31e16416e7ef4a629d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 10 Mar 2022 10:54:27 +0100 Subject: [PATCH] created new dual lane assembly base --- bsp_q7s/core/CoreController.cpp | 2 +- mission/system/AcsBoardAssembly.cpp | 118 +++--------------------- mission/system/AcsBoardAssembly.h | 33 ++----- mission/system/CMakeLists.txt | 1 + mission/system/DualLaneAssemblyBase.cpp | 92 ++++++++++++++++++ mission/system/DualLaneAssemblyBase.h | 66 +++++++++++++ 6 files changed, 178 insertions(+), 134 deletions(-) create mode 100644 mission/system/DualLaneAssemblyBase.cpp create mode 100644 mission/system/DualLaneAssemblyBase.h diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 6c176eb1..89d9ce14 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -4,9 +4,9 @@ #include "OBSWConfig.h" #include "OBSWVersion.h" -#include "fsfw/version.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/timemanager/Stopwatch.h" +#include "fsfw/version.h" #include "watchdogConf.h" #if OBSW_USE_TMTC_TCP_BRIDGE == 0 #include "fsfw/osal/common/UdpTmTcBridge.h" diff --git a/mission/system/AcsBoardAssembly.cpp b/mission/system/AcsBoardAssembly.cpp index 286bb106..76e2d916 100644 --- a/mission/system/AcsBoardAssembly.cpp +++ b/mission/system/AcsBoardAssembly.cpp @@ -6,8 +6,8 @@ AcsBoardAssembly::AcsBoardAssembly(object_id_t objectId, object_id_t parentId, PowerSwitchIF* switcher, AcsBoardHelper helper, GpioIF* gpioIF) - : AssemblyBase(objectId, parentId), - pwrStateMachine(SWITCH_A, SWITCH_B, switcher), + : DualLaneAssemblyBase(objectId, parentId, switcher, SWITCH_A, SWITCH_B, + POWER_STATE_MACHINE_TIMEOUT), helper(helper), gpioIF(gpioIF) { if (switcher == nullptr) { @@ -19,46 +19,15 @@ AcsBoardAssembly::AcsBoardAssembly(object_id_t objectId, object_id_t parentId, sif::error << "AcsBoardAssembly::AcsBoardAssembly: Invalid GPIO IF passed" << std::endl; } ModeListEntry entry; - initModeTableEntry(helper.mgm0Lis3IdSideA, entry); - initModeTableEntry(helper.mgm1Rm3100IdSideA, entry); - initModeTableEntry(helper.mgm2Lis3IdSideB, entry); - initModeTableEntry(helper.mgm3Rm3100IdSideB, entry); - initModeTableEntry(helper.gyro0AdisIdSideA, entry); - initModeTableEntry(helper.gyro1L3gIdSideA, entry); - initModeTableEntry(helper.gyro2AdisIdSideB, entry); - initModeTableEntry(helper.gyro3L3gIdSideB, entry); - initModeTableEntry(helper.gpsId, entry); -} - -void AcsBoardAssembly::performChildOperation() { - using namespace duallane; - if (pwrStateMachine.active()) { - pwrStateMachineWrapper(); - // This state is the indicator that the power state machine is done - } - if (not pwrStateMachine.active()) { - AssemblyBase::performChildOperation(); - } -} - -void AcsBoardAssembly::startTransition(Mode_t mode, Submode_t submode) { - using namespace duallane; - pwrStateMachine.reset(); - // If anything other than MODE_OFF is commanded, perform power state machine first - if (mode != MODE_OFF) { - // Cache the target modes, required by power state machine - pwrStateMachine.start(mode, submode); - // Cache these for later after the power state machine has finished - targetMode = mode; - targetSubmode = submode; - // Perform power state machine first, then start mode transition. The power state machine will - // start the transition after it has finished - pwrStateMachineWrapper(); - } else { - // Command the devices to off first before switching off the power. The handleModeReached - // custom implementation will take care of starting the power state machine. - AssemblyBase::startTransition(mode, submode); - } + initModeTableEntry(helper.mgm0Lis3IdSideA, entry, modeTable); + initModeTableEntry(helper.mgm1Rm3100IdSideA, entry, modeTable); + initModeTableEntry(helper.mgm2Lis3IdSideB, entry, modeTable); + initModeTableEntry(helper.mgm3Rm3100IdSideB, entry, modeTable); + initModeTableEntry(helper.gyro0AdisIdSideA, entry, modeTable); + initModeTableEntry(helper.gyro1L3gIdSideA, entry, modeTable); + initModeTableEntry(helper.gyro2AdisIdSideB, entry, modeTable); + initModeTableEntry(helper.gyro3L3gIdSideB, entry, modeTable); + initModeTableEntry(helper.gpsId, entry, modeTable); } ReturnValue_t AcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) { @@ -95,11 +64,6 @@ ReturnValue_t AcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) ReturnValue_t AcsBoardAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) { using namespace duallane; refreshHelperModes(); - // if (state == PwrStates::SWITCHING_POWER) { - // // Wrong mode - // sif::error << "Wrong mode, currently switching power" << std::endl; - // return RETURN_OK; - // } if (wantedSubmode == A_SIDE) { if ((helper.gyro0SideAMode != wantedMode and helper.gyro1SideAMode != wantedMode) or (helper.mgm0SideAMode != wantedMode and helper.mgm1SideAMode != wantedMode) or @@ -245,34 +209,6 @@ ReturnValue_t AcsBoardAssembly::isModeCombinationValid(Mode_t mode, Submode_t su return HasReturnvaluesIF::RETURN_OK; } -bool AcsBoardAssembly::isUseable(object_id_t object, Mode_t mode) { - if (healthHelper.healthTable->isFaulty(object)) { - return false; - } - - // Check if device is already in target mode - if (childrenMap[object].mode == mode) { - return true; - } - - if (healthHelper.healthTable->isCommandable(object)) { - return true; - } - return false; -} - -void AcsBoardAssembly::handleModeReached() { - using namespace duallane; - if (targetMode == MODE_OFF) { - pwrStateMachine.start(targetMode, targetSubmode); - // Now we can switch off the power. After that, the AssemblyBase::handleModeReached function - // will be called - pwrStateMachineWrapper(); - } else { - finishModeOp(); - } -} - void AcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) { using namespace duallane; // Some ACS board components are required for Safe-Mode. It would be good if the software @@ -357,14 +293,6 @@ void AcsBoardAssembly::refreshHelperModes() { } } -void AcsBoardAssembly::initModeTableEntry(object_id_t id, ModeListEntry& entry) { - entry.setObject(id); - entry.setMode(MODE_OFF); - entry.setSubmode(SUBMODE_NONE); - entry.setInheritSubmode(false); - modeTable.insert(entry); -} - void AcsBoardAssembly::finishModeOp() { using namespace duallane; AssemblyBase::handleModeReached(); @@ -374,30 +302,6 @@ void AcsBoardAssembly::finishModeOp() { dualModeErrorSwitch = true; } -ReturnValue_t AcsBoardAssembly::pwrStateMachineWrapper() { - using namespace duallane; - OpCodes opCode = pwrStateMachine.powerStateMachine(); - if (opCode == OpCodes::NONE) { - return RETURN_OK; - } else if (opCode == OpCodes::FINISH_OP) { - finishModeOp(); - } else if (opCode == OpCodes::START_TRANSITION) { - AssemblyBase::startTransition(targetMode, targetSubmode); - } else if (opCode == OpCodes::TIMEOUT_OCCURED) { - if (powerRetryCounter == 0) { - powerRetryCounter++; - pwrStateMachine.reset(); - } else { -#if OBSW_VERBOSE_LEVEL >= 1 - sif::warning << "Timeout occured in power state machine" << std::endl; -#endif - triggerEvent(POWER_STATE_MACHINE_TIMEOUT, 0, 0); - return RETURN_FAILED; - } - } - return RETURN_OK; -} - ReturnValue_t AcsBoardAssembly::initialize() { ReturnValue_t result = registerChild(helper.gyro0AdisIdSideA); if (result != HasReturnvaluesIF::RETURN_OK) { diff --git a/mission/system/AcsBoardAssembly.h b/mission/system/AcsBoardAssembly.h index 7f2a85fa..20b8d748 100644 --- a/mission/system/AcsBoardAssembly.h +++ b/mission/system/AcsBoardAssembly.h @@ -3,9 +3,9 @@ #include #include -#include #include +#include "DualLaneAssemblyBase.h" #include "DualLanePowerStateMachine.h" struct AcsBoardHelper { @@ -71,15 +71,15 @@ class GpioIF; * doing this task would be performed by the device handlers, but this is not possible for the * ACS board where multiple sensors share the same power supply. */ -class AcsBoardAssembly : public AssemblyBase { +class AcsBoardAssembly : public DualLaneAssemblyBase { public: static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::ACS_BOARD_ASS; static constexpr Event TRANSITION_OTHER_SIDE_FAILED = - event::makeEvent(SUBSYSTEM_ID, 0, severity::HIGH); + event::makeEvent(SUBSYSTEM_ID, TRANSITION_OTHER_SIDE_FAILED_ID, severity::HIGH); static constexpr Event NOT_ENOUGH_DEVICES_DUAL_MODE = - event::makeEvent(SUBSYSTEM_ID, 1, severity::HIGH); + event::makeEvent(SUBSYSTEM_ID, NOT_ENOUGH_DEVICES_DUAL_MODE_ID, severity::HIGH); static constexpr Event POWER_STATE_MACHINE_TIMEOUT = - event::makeEvent(SUBSYSTEM_ID, 2, severity::MEDIUM); + event::makeEvent(SUBSYSTEM_ID, POWER_STATE_MACHINE_TIMEOUT_ID, severity::MEDIUM); static constexpr uint8_t NUMBER_DEVICES_MODE_TABLE = 9; @@ -101,12 +101,10 @@ class AcsBoardAssembly : public AssemblyBase { static constexpr pcduSwitches::Switches SWITCH_B = pcduSwitches::Switches::PDU2_CH7_ACS_BOARD_SIDE_B_3V3; - // This helper object complete encapsulates power switching - DualLanePowerStateMachine pwrStateMachine; bool tryingOtherSide = false; AcsBoardHelper helper; GpioIF* gpioIF = nullptr; - uint8_t powerRetryCounter = 0; + // duallane::PwrStates state = duallane::PwrStates::IDLE; duallane::Submodes defaultSubmode = duallane::Submodes::A_SIDE; bool dualModeErrorSwitch = true; @@ -118,30 +116,13 @@ class AcsBoardAssembly : public AssemblyBase { 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 performChildOperation() override; - void startTransition(Mode_t mode, Submode_t submode) override; - void handleModeReached() override; + void handleModeTransitionFailed(ReturnValue_t result) override; void handleChildrenLostMode(ReturnValue_t result) override; - /** - * 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); ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode); - void initModeTableEntry(object_id_t id, ModeListEntry& entry); void refreshHelperModes(); void finishModeOp(); - /** - * Thin wrapper function which is required because the helper class - * can not access protected member functions. - * @param mode - * @param submode - */ - ReturnValue_t pwrStateMachineWrapper(); }; #endif /* MISSION_SYSTEM_ACSBOARDASSEMBLY_H_ */ diff --git a/mission/system/CMakeLists.txt b/mission/system/CMakeLists.txt index fb8d7096..333de2f9 100644 --- a/mission/system/CMakeLists.txt +++ b/mission/system/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(${LIB_EIVE_MISSION} PRIVATE ComSubsystem.cpp TcsSubsystem.cpp DualLanePowerStateMachine.cpp + DualLaneAssemblyBase.cpp ) \ No newline at end of file diff --git a/mission/system/DualLaneAssemblyBase.cpp b/mission/system/DualLaneAssemblyBase.cpp new file mode 100644 index 00000000..8ed549b1 --- /dev/null +++ b/mission/system/DualLaneAssemblyBase.cpp @@ -0,0 +1,92 @@ +#include "DualLaneAssemblyBase.h" + +DualLaneAssemblyBase::DualLaneAssemblyBase(object_id_t objectId, object_id_t parentId, + PowerSwitchIF* pwrSwitcher, + pcduSwitches::Switches switch1, + pcduSwitches::Switches switch2, Event pwrTimeoutEvent) + : AssemblyBase(objectId, parentId), + pwrStateMachine(switch1, switch2, pwrSwitcher), + pwrTimeoutEvent(pwrTimeoutEvent) {} + +void DualLaneAssemblyBase::performChildOperation() { + using namespace duallane; + if (pwrStateMachine.active()) { + pwrStateMachineWrapper(); + // This state is the indicator that the power state machine is done + } + if (not pwrStateMachine.active()) { + AssemblyBase::performChildOperation(); + } +} + +void DualLaneAssemblyBase::startTransition(Mode_t mode, Submode_t submode) { + using namespace duallane; + pwrStateMachine.reset(); + // If anything other than MODE_OFF is commanded, perform power state machine first + if (mode != MODE_OFF) { + // Cache the target modes, required by power state machine + pwrStateMachine.start(mode, submode); + // Cache these for later after the power state machine has finished + targetMode = mode; + targetSubmode = submode; + // Perform power state machine first, then start mode transition. The power state machine will + // start the transition after it has finished + pwrStateMachineWrapper(); + } else { + // Command the devices to off first before switching off the power. The handleModeReached + // custom implementation will take care of starting the power state machine. + AssemblyBase::startTransition(mode, submode); + } +} + +bool DualLaneAssemblyBase::isUseable(object_id_t object, Mode_t mode) { + if (healthHelper.healthTable->isFaulty(object)) { + return false; + } + + // Check if device is already in target mode + if (childrenMap[object].mode == mode) { + return true; + } + + if (healthHelper.healthTable->isCommandable(object)) { + return true; + } + return false; +} + +ReturnValue_t DualLaneAssemblyBase::pwrStateMachineWrapper() { + using namespace duallane; + OpCodes opCode = pwrStateMachine.powerStateMachine(); + if (opCode == OpCodes::NONE) { + return RETURN_OK; + } else if (opCode == OpCodes::FINISH_OP) { + finishModeOp(); + } else if (opCode == OpCodes::START_TRANSITION) { + AssemblyBase::startTransition(targetMode, targetSubmode); + } else if (opCode == OpCodes::TIMEOUT_OCCURED) { + if (powerRetryCounter == 0) { + powerRetryCounter++; + pwrStateMachine.reset(); + } else { +#if OBSW_VERBOSE_LEVEL >= 1 + sif::warning << "Timeout occured in power state machine" << std::endl; +#endif + triggerEvent(pwrTimeoutEvent, 0, 0); + return RETURN_FAILED; + } + } + return RETURN_OK; +} + +void DualLaneAssemblyBase::handleModeReached() { + using namespace duallane; + if (targetMode == MODE_OFF) { + pwrStateMachine.start(targetMode, targetSubmode); + // Now we can switch off the power. After that, the AssemblyBase::handleModeReached function + // will be called + pwrStateMachineWrapper(); + } else { + finishModeOp(); + } +} diff --git a/mission/system/DualLaneAssemblyBase.h b/mission/system/DualLaneAssemblyBase.h new file mode 100644 index 00000000..79037efa --- /dev/null +++ b/mission/system/DualLaneAssemblyBase.h @@ -0,0 +1,66 @@ +#ifndef MISSION_SYSTEM_DUALLANEASSEMBLYBASE_H_ +#define MISSION_SYSTEM_DUALLANEASSEMBLYBASE_H_ + +#include +#include + +class DualLaneAssemblyBase : public AssemblyBase { + public: + static constexpr uint8_t TRANSITION_OTHER_SIDE_FAILED_ID = 0; + static constexpr uint8_t NOT_ENOUGH_DEVICES_DUAL_MODE_ID = 1; + static constexpr uint8_t POWER_STATE_MACHINE_TIMEOUT_ID = 2; + + DualLaneAssemblyBase(object_id_t objectId, object_id_t parentId, PowerSwitchIF* pwrSwitcher, + pcduSwitches::Switches switch1, pcduSwitches::Switches switch2, + Event pwrSwitchTimeoutEvent); + + virtual void performChildOperation() override; + virtual void startTransition(Mode_t mode, Submode_t submode) override; + + protected: + // This helper object complete encapsulates power switching + DualLanePowerStateMachine pwrStateMachine; + Event pwrTimeoutEvent; + uint8_t powerRetryCounter = 0; + + /** + * 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); + /** + * Thin wrapper function which is required because the helper class + * can not access protected member functions. + * @param mode + * @param submode + */ + virtual ReturnValue_t pwrStateMachineWrapper(); + virtual void handleModeReached(); + + /** + * Implemented by user. Will be called if a full mode operation has finished. + * This includes both the regular mode state machine operations and the power state machine + * operations + */ + virtual void finishModeOp() = 0; + + template + void initModeTableEntry(object_id_t id, ModeListEntry& entry, + FixedArrayList& modeTable); + + private: +}; + +template +inline void DualLaneAssemblyBase::initModeTableEntry( + object_id_t id, ModeListEntry& entry, FixedArrayList& modeTable) { + entry.setObject(id); + entry.setMode(MODE_OFF); + entry.setSubmode(SUBMODE_NONE); + entry.setInheritSubmode(false); + modeTable.insert(entry); +} + +#endif /* MISSION_SYSTEM_DUALLANEASSEMBLYBASE_H_ */