From 397e23f1daae78eb98bcc903ae55f925c1fdc462 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:13:24 +0200 Subject: [PATCH 01/45] more TCS tests --- CMakeLists.txt | 3 + bsp_hosted/scheduling.cpp | 1 - bsp_q7s/OBSWConfig.h.in | 1 + bsp_q7s/core/scheduling.cpp | 5 +- dummies/TemperatureSensorInserter.cpp | 73 ++++++----- dummies/TemperatureSensorInserter.h | 5 +- mission/controller/ThermalController.cpp | 116 +++++++++++------- mission/controller/ThermalController.h | 20 +-- mission/controller/tcsDefs.h | 2 +- mission/system/tree/tcsModeTree.cpp | 2 +- mission/tcs/HeaterHandler.cpp | 18 +-- mission/tcs/HeaterHandler.h | 12 +- .../tcs/defs.h | 8 +- 13 files changed, 155 insertions(+), 111 deletions(-) rename common/config/devices/heaterSwitcherList.h => mission/tcs/defs.h (55%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8724476..784fb9c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,9 @@ set(OBSW_ADD_SUN_SENSORS set(OBSW_ADD_SUS_BOARD_ASS ${INIT_VAL} CACHE STRING "Add sun sensor board assembly") +set(OBSW_ADD_THERMAL_TEMP_INSERTER + ${INIT_VAL} + CACHE STRING "Add thermal sensor temperature inserter") set(OBSW_ADD_ACS_BOARD ${INIT_VAL} CACHE STRING "Add ACS board module") diff --git a/bsp_hosted/scheduling.cpp b/bsp_hosted/scheduling.cpp index 600a94e1..0a5f1c35 100644 --- a/bsp_hosted/scheduling.cpp +++ b/bsp_hosted/scheduling.cpp @@ -151,7 +151,6 @@ void scheduling::initTasks() { if (result != returnvalue::OK) { scheduling::printAddObjectError("Core controller dummy", objects::CORE_CONTROLLER); } - result = thermalTask->addComponent(objects::THERMAL_CONTROLLER); if (result != returnvalue::OK) { scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER); diff --git a/bsp_q7s/OBSWConfig.h.in b/bsp_q7s/OBSWConfig.h.in index 272467b5..b60472d6 100644 --- a/bsp_q7s/OBSWConfig.h.in +++ b/bsp_q7s/OBSWConfig.h.in @@ -43,6 +43,7 @@ #define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@ #define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@ #define OBSW_ADD_CCSDS_IP_CORES @OBSW_ADD_CCSDS_IP_CORES@ +#define OBSW_ADD_THERMAL_TEMP_INSERTER @OBSW_ADD_THERMAL_TEMP_INSERTER@ // Set to 1 if all telemetry should be sent to the PTME IP Core #define OBSW_TM_TO_PTME @OBSW_TM_TO_PTME@ // Set to 1 if telecommands are received via the PDEC IP Core diff --git a/bsp_q7s/core/scheduling.cpp b/bsp_q7s/core/scheduling.cpp index e248938a..9d727335 100644 --- a/bsp_q7s/core/scheduling.cpp +++ b/bsp_q7s/core/scheduling.cpp @@ -302,6 +302,9 @@ void scheduling::initTasks() { PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask( "TCS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING); +#if OBSW_ADD_THERMAL_TEMP_INSERTER == 1 + tcsSystemTask->addComponent(objects::THERMAL_TEMP_INSERTER); +#endif scheduling::scheduleRtdSensors(tcsSystemTask); result = tcsSystemTask->addComponent(objects::TCS_SUBSYSTEM); if (result != returnvalue::OK) { @@ -317,12 +320,10 @@ void scheduling::initTasks() { scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER); } #endif -#if OBSW_ADD_HEATERS == 1 result = tcsSystemTask->addComponent(objects::HEATER_HANDLER); if (result != returnvalue::OK) { scheduling::printAddObjectError("HEATER_HANDLER", objects::HEATER_HANDLER); } -#endif #if OBSW_ADD_SYRLINKS == 1 PeriodicTaskIF* syrlinksCom = factory->createPeriodicTask( diff --git a/dummies/TemperatureSensorInserter.cpp b/dummies/TemperatureSensorInserter.cpp index 3d268953..11d31779 100644 --- a/dummies/TemperatureSensorInserter.cpp +++ b/dummies/TemperatureSensorInserter.cpp @@ -1,5 +1,6 @@ #include "TemperatureSensorInserter.h" +#include #include #include @@ -14,10 +15,7 @@ TemperatureSensorInserter::TemperatureSensorInserter(object_id_t objectId, tmp1075DummyMap(std::move(tempTmpSensorDummies_)) {} ReturnValue_t TemperatureSensorInserter::initialize() { - if (performTest) { - if (testCase == TestCase::COOL_SYRLINKS) { - } - } + testCase = TestCase::COOL_MGT; return returnvalue::OK; } @@ -33,35 +31,46 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { tempsWereInitialized = true; } - if (cycles == 10) { - max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-100, true); - max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(-100, true); + switch (testCase) { + case (TestCase::NONE): { + break; + } + case (TestCase::COOL_SYRLINKS): { + // TODO: How do I insert this? + // Does not work on EM, where a real syrlinks device is connected. + if (cycles == 15) { + lp_var_t tempSyrlinksBasebandBoard = + lp_var_t(objects::SYRLINKS_HANDLER, syrlinks::TEMP_BASEBAND_BOARD); + PoolReadGuard pg(&tempSyrlinksBasebandBoard); + tempSyrlinksBasebandBoard.value = -50; + } + if (cycles == 30) { + lp_var_t tempSyrlinksBasebandBoard = + lp_var_t(objects::SYRLINKS_HANDLER, syrlinks::TEMP_BASEBAND_BOARD); + PoolReadGuard pg(&tempSyrlinksBasebandBoard); + tempSyrlinksBasebandBoard.value = 0; + } + break; + } + case (TestCase::COOL_HPA): { + if (cycles == 15) { + max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-60, true); + } + if (cycles == 30) { + max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(0, true); + } + break; + } + case (TestCase::COOL_MGT): { + if (cycles == 15) { + max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(-60, true); + } + if (cycles == 30) { + max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(0, true); + } + break; + } } - - if (cycles == 35) { - max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(0, true); - max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(0, true); - max31865DummyMap[objects::RTD_2_IC5_4K_CAMERA]->setTemperature(-100, true); - } - if (cycles == 60) { - max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-100, true); - max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(0, true); - } - - /* - ReturnValue_t result = max31865PlocHeatspreaderSet.read(); - if (result != returnvalue::OK) { - sif::warning << "Failed to read temperature from MAX31865 dataset" << std::endl; - } - max31865PlocHeatspreaderSet.rtdValue = value - 5; - max31865PlocHeatspreaderSet.temperatureCelcius = value; - if ((iteration % 100) < 20) { - max31865PlocHeatspreaderSet.setValidity(false, true); - } else { - max31865PlocHeatspreaderSet.setValidity(true, true); - } - max31865PlocHeatspreaderSet.commit(); - */ cycles++; return returnvalue::OK; } diff --git a/dummies/TemperatureSensorInserter.h b/dummies/TemperatureSensorInserter.h index 0c05cf34..1727e735 100644 --- a/dummies/TemperatureSensorInserter.h +++ b/dummies/TemperatureSensorInserter.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "Max31865Dummy.h" @@ -22,11 +23,11 @@ class TemperatureSensorInserter : public ExecutableObjectIF, public SystemObject private: Max31865DummyMap max31865DummyMap; Tmp1075DummyMap tmp1075DummyMap; - enum TestCase { NONE = 0, COOL_SYRLINKS = 1 }; + + enum TestCase { NONE = 0, COOL_SYRLINKS = 1, COOL_HPA = 2, COOL_MGT = 3 }; int iteration = 0; uint32_t cycles = 0; bool tempsWereInitialized = false; - bool performTest = false; TestCase testCase = TestCase::NONE; // void noise(); diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 96b6de86..e06e568d 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -166,26 +166,30 @@ void ThermalController::performControlOperation() { } } - if (transitionToOff) { - for (const auto& switchState : heaterSwitchStateArray) { - if (switchState != HeaterHandler::SwitchState::OFF) { - transitionToOffCycles++; - // if heater still ON after 10 cycles, switch OFF again - if (transitionToOffCycles == 10) { - for (uint8_t i = 0; i < heater::Switchers::NUMBER_OF_SWITCHES; i++) { - heaterHandler.switchHeater(static_cast(i), - HeaterHandler::SwitchState::OFF); - } + cycles++; + if (transitionWhenHeatersOff) { + bool allSwitchersOff = true; + for (size_t idx = 0; idx < heaterSwitchStateArray.size(); idx++) { + if (heaterSwitchStateArray[idx] != HeaterHandler::SwitchState::OFF) { + allSwitchersOff = false; + // if heater still ON after 3 cycles, switch OFF again + if (transitionWhenHeatersOffCycles == 3) { + heaterHandler.switchHeater(static_cast(idx), + HeaterHandler::SwitchState::OFF); triggerEvent(tcsCtrl::HEATER_NOT_OFF_FOR_OFF_MODE); } - return; } - setMode(MODE_OFF); + } + if (allSwitchersOff or transitionWhenHeatersOffCycles == 6) { + // Finish the transition + transitionWhenHeatersOff = false; + setMode(targetMode, targetSubmode); + } else { + transitionWhenHeatersOffCycles++; } } else if (mode != MODE_OFF) { performThermalModuleCtrl(heaterSwitchStateArray); } - cycles++; } ReturnValue_t ThermalController::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, @@ -288,12 +292,18 @@ LocalPoolDataSetBase* ThermalController::getDataSetHandle(sid_t sid) { ReturnValue_t ThermalController::checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode) { + if ((mode != MODE_OFF) and (mode != MODE_ON)) { + return INVALID_MODE; + } + if (mode == MODE_ON) { + if (submode != SUBMODE_NONE and submode != SUBMODE_NO_HEATER_CTRL) { + return HasModesIF::INVALID_SUBMODE; + } + return returnvalue::OK; + } if (submode != SUBMODE_NONE) { return INVALID_SUBMODE; } - if ((mode != MODE_OFF) && (mode != MODE_ON) && (mode != MODE_NORMAL)) { - return INVALID_MODE; - } return returnvalue::OK; } @@ -972,8 +982,8 @@ void ThermalController::copyDevices() { } void ThermalController::ctrlAcsBoard() { - heater::Switchers switchNr = heater::HEATER_2_ACS_BRD; - heater::Switchers redSwitchNr = heater::HEATER_0_OBC_BRD; + heater::Switch switchNr = heater::HEATER_2_ACS_BRD; + heater::Switch redSwitchNr = heater::HEATER_0_OBC_BRD; // A side thermalComponent = ACS_BOARD; @@ -1019,7 +1029,9 @@ void ThermalController::ctrlAcsBoard() { } else { if (chooseHeater(switchNr, redSwitchNr)) { if (heaterHandler.getSwitchState(switchNr)) { - heaterHandler.switchHeater(switchNr, HeaterHandler::SwitchState::OFF); + if (submode != SUBMODE_NO_HEATER_CTRL) { + heaterHandler.switchHeater(switchNr, HeaterHandler::SwitchState::OFF); + } } } } @@ -1264,8 +1276,8 @@ void ThermalController::ctrlPcduP60Board() { void ThermalController::ctrlPcduAcu() { thermalComponent = PCDUACU; - heater::Switchers switchNr = heater::HEATER_3_PCDU_PDU; - heater::Switchers redSwitchNr = heater::HEATER_2_ACS_BRD; + heater::Switch switchNr = heater::HEATER_3_PCDU_PDU; + heater::Switch redSwitchNr = heater::HEATER_2_ACS_BRD; if (chooseHeater(switchNr, redSwitchNr)) { bool sensorTempAvailable = true; @@ -1556,10 +1568,13 @@ void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { checkLimitsAndCtrlHeater(htrCtx); } } else { - // TODO: muss der Heater dann wirklich abgeschalten werden? + // No sensors available, so switch the heater off. We can not perform control tasks if we + // are blind.. if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { - if (heaterHandler.getSwitchState(htrCtx.switchNr)) { - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); + if (submode != SUBMODE_NO_HEATER_CTRL) { + if (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON) { + heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); + } } } } @@ -1589,7 +1604,7 @@ bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) { return false; } -bool ThermalController::chooseHeater(heater::Switchers& switchNr, heater::Switchers redSwitchNr) { +bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr) { bool heaterAvailable = true; if (heaterHandler.getHealth(switchNr) != HasHealthIF::HEALTHY) { @@ -1608,15 +1623,19 @@ bool ThermalController::chooseHeater(heater::Switchers& switchNr, heater::Switch void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) { if (htrCtx.switchState == HeaterHandler::SwitchState::ON) { - sif::info << "TCS: Component " << static_cast(thermalComponent) << " too warm, above " - << whatLimit << ", switching off heater" << std::endl; - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); - heaterStates[htrCtx.switchNr].switchTransition = true; + if (submode != SUBMODE_NO_HEATER_CTRL) { + sif::info << "TCS: Component " << static_cast(thermalComponent) << " too warm, above " + << whatLimit << ", switching off heater" << std::endl; + heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); + heaterStates[htrCtx.switchNr].switchTransition = true; + } heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; } if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == HeaterHandler::SwitchState::ON) { - heaterHandler.switchHeater(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF); - heaterStates[htrCtx.redSwitchNr].switchTransition = true; + if (submode != SUBMODE_NO_HEATER_CTRL) { + heaterHandler.switchHeater(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF); + heaterStates[htrCtx.redSwitchNr].switchTransition = true; + } heaterStates[htrCtx.redSwitchNr].target = HeaterHandler::SwitchState::OFF; } } @@ -1634,14 +1653,14 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { // Heater off htrCtx.switchState = heaterHandler.getSwitchState(htrCtx.switchNr); if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) { - if (sensorTemp < htrCtx.tempLimit.opLowerLimit) { + if (sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) { heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::ON); - sif::info << "ThermalController::checkLimitsAndCtrlHeater: Heater " - << static_cast(thermalComponent) << " ON" << std::endl; + sif::info << "TCS: Heater " << static_cast(thermalComponent) << " ON" << std::endl; heaterStates[htrCtx.switchNr].switchTransition = true; thermalStates[thermalComponent].heating = true; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::ON; } else { + // Even if heater control is now allowed, we can update the state. thermalStates[thermalComponent].heating = false; } heaterCtrlCheckUpperLimits(htrCtx); @@ -1649,10 +1668,9 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { } else if (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON) { if (thermalStates[thermalComponent].heating) { // We are already in a heating cycle, so need to check whether heating task is complete. - if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET) { + if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET and heaterCtrlAllowed()) { heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); - sif::info << "ThermalController::checkLimitsAndCtrlHeater: Heater " - << static_cast(thermalComponent) << " OFF" << std::endl; + sif::info << "TCS: Heater" << static_cast(thermalComponent) << " OFF" << std::endl; heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; thermalStates[thermalComponent].heating = false; @@ -1723,11 +1741,12 @@ uint32_t ThermalController::tempFloatToU32() const { return tempRaw; } -void ThermalController::setMode(Mode_t mode) { +void ThermalController::setMode(Mode_t mode, Submode_t submode) { if (mode == MODE_OFF) { - transitionToOff = false; + transitionWhenHeatersOff = false; } this->mode = mode; + this->submode = submode; modeHelper.modeChanged(mode, submode); announceMode(false); } @@ -1742,6 +1761,8 @@ bool ThermalController::tooHotHandler(object_id_t object, bool& oneShotFlag) { return false; } +bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO_HEATER_CTRL; } + void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag) { // Clear the one shot flag is the component is in acceptable temperature range. if (not tooHotHandler(object, oneShotFlag) and not componentAboveUpperLimit) { @@ -1751,14 +1772,17 @@ void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, void ThermalController::startTransition(Mode_t mode_, Submode_t submode_) { triggerEvent(CHANGING_MODE, mode_, submode_); - if (mode_ == MODE_OFF) { - for (uint8_t i = 0; i < heater::Switchers::NUMBER_OF_SWITCHES; i++) { - heaterHandler.switchHeater(static_cast(i), - HeaterHandler::SwitchState::OFF); + // For MODE_OFF and the no heater control submode, we command all switches to off before + // completing the transition. This ensures a consistent state when commanding these modes. + if ((mode_ == MODE_OFF) or ((mode_ == MODE_ON) and (submode_ == SUBMODE_NO_HEATER_CTRL))) { + for (uint8_t i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { + heaterHandler.switchHeater(static_cast(i), HeaterHandler::SwitchState::OFF); } - transitionToOff = true; - transitionToOffCycles = 0; + transitionWhenHeatersOff = true; + targetMode = mode_; + targetSubmode = submode_; + transitionWhenHeatersOffCycles = 0; } else { - setMode(mode_); + setMode(mode_, submode_); } } diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index d531e813..34ffcd49 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -89,6 +89,8 @@ enum ThermalComponents : uint8_t { class ThermalController : public ExtendedControllerBase { public: + static constexpr uint8_t SUBMODE_NO_HEATER_CTRL = 1; + static const uint16_t INVALID_TEMPERATURE = 999; static const uint8_t NUMBER_OF_SENSORS = 16; static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; @@ -101,13 +103,13 @@ class ThermalController : public ExtendedControllerBase { protected: struct HeaterContext { public: - HeaterContext(heater::Switchers switchNr, heater::Switchers redundantSwitchNr, + HeaterContext(heater::Switch switchNr, heater::Switch redundantSwitchNr, const TempLimits& tempLimit) : switchNr(switchNr), redSwitchNr(redundantSwitchNr), tempLimit(tempLimit) {} bool doHeaterHandling = true; - heater::Switchers switchNr; + heater::Switch switchNr; HeaterHandler::SwitchState switchState = HeaterHandler::SwitchState::OFF; - heater::Switchers redSwitchNr; + heater::Switch redSwitchNr; const TempLimits& tempLimit; }; @@ -261,8 +263,10 @@ class ThermalController : public ExtendedControllerBase { bool strTooHotFlag = false; bool rwTooHotFlag = false; - bool transitionToOff = false; - uint32_t transitionToOffCycles = 0; + bool transitionWhenHeatersOff = false; + uint32_t transitionWhenHeatersOffCycles = 0; + Mode_t targetMode = MODE_OFF; + Submode_t targetSubmode = SUBMODE_NONE; uint32_t cycles = 0; std::array thermalStates{}; std::array heaterStates{}; @@ -290,6 +294,8 @@ class ThermalController : public ExtendedControllerBase { void startTransition(Mode_t mode, Submode_t submode) override; + bool heaterCtrlAllowed() const; + void resetSensorsArray(); void copySensors(); void copySus(); @@ -300,7 +306,7 @@ class ThermalController : public ExtendedControllerBase { bool heaterCtrlCheckUpperLimits(HeaterContext& heaterContext); void heaterCtrlTempTooHighHandler(HeaterContext& heaterContext, const char* whatLimit); - bool chooseHeater(heater::Switchers& switchNr, heater::Switchers redSwitchNr); + bool chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr); bool selectAndReadSensorTemp(HeaterContext& htrCtx); void ctrlAcsBoard(); @@ -327,7 +333,7 @@ class ThermalController : public ExtendedControllerBase { void ctrlMpa(); void ctrlScexBoard(); void heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates); - void setMode(Mode_t mode); + void setMode(Mode_t mode, Submode_t submode); uint32_t tempFloatToU32() const; bool tooHotHandler(object_id_t object, bool& oneShotFlag); void tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag); diff --git a/mission/controller/tcsDefs.h b/mission/controller/tcsDefs.h index e187091b..03aa8ffe 100644 --- a/mission/controller/tcsDefs.h +++ b/mission/controller/tcsDefs.h @@ -4,8 +4,8 @@ #include #include -#include "devices/heaterSwitcherList.h" #include "eive/eventSubsystemIds.h" +#include "mission/tcs/defs.h" namespace tcsCtrl { diff --git a/mission/system/tree/tcsModeTree.cpp b/mission/system/tree/tcsModeTree.cpp index b7188b17..9e48b10b 100644 --- a/mission/system/tree/tcsModeTree.cpp +++ b/mission/system/tree/tcsModeTree.cpp @@ -111,7 +111,7 @@ void buildNormalSequence(Subsystem& ss, ModeListEntry& eh) { ctxc); // Transition 1 - iht(objects::THERMAL_CONTROLLER, NML, 0, TCS_TABLE_NORMAL_TRANS_1.second); + iht(objects::THERMAL_CONTROLLER, HasModesIF::MODE_ON, 0, TCS_TABLE_NORMAL_TRANS_1.second); check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TRANS_1.first, &TCS_TABLE_NORMAL_TRANS_1.second)), ctxc); diff --git a/mission/tcs/HeaterHandler.cpp b/mission/tcs/HeaterHandler.cpp index 4ec82c08..55cc99cb 100644 --- a/mission/tcs/HeaterHandler.cpp +++ b/mission/tcs/HeaterHandler.cpp @@ -215,17 +215,17 @@ void HeaterHandler::handleSwitchHandling() { heaterVec[idx].cmdActive = true; heaterVec[idx].action = SET_SWITCH_OFF; triggerEvent(FAULTY_HEATER_WAS_ON, idx, 0); - handleSwitchOffCommand(static_cast(idx)); + handleSwitchOffCommand(static_cast(idx)); continue; } } if (heaterVec[idx].cmdActive) { switch (heaterVec[idx].action) { case SET_SWITCH_ON: - handleSwitchOnCommand(static_cast(idx)); + handleSwitchOnCommand(static_cast(idx)); break; case SET_SWITCH_OFF: - handleSwitchOffCommand(static_cast(idx)); + handleSwitchOffCommand(static_cast(idx)); break; default: sif::error << "HeaterHandler::handleActiveCommands: Invalid action commanded" @@ -236,7 +236,7 @@ void HeaterHandler::handleSwitchHandling() { } } -void HeaterHandler::handleSwitchOnCommand(heater::Switchers heaterIdx) { +void HeaterHandler::handleSwitchOnCommand(heater::Switch heaterIdx) { ReturnValue_t result = returnvalue::OK; auto& heater = heaterVec.at(heaterIdx); if (waitForSwitchOff) { @@ -307,7 +307,7 @@ void HeaterHandler::handleSwitchOnCommand(heater::Switchers heaterIdx) { } } -void HeaterHandler::handleSwitchOffCommand(heater::Switchers heaterIdx) { +void HeaterHandler::handleSwitchOffCommand(heater::Switch heaterIdx) { ReturnValue_t result = returnvalue::OK; auto& heater = heaterVec.at(heaterIdx); // Check whether switch is already off @@ -345,12 +345,12 @@ void HeaterHandler::handleSwitchOffCommand(heater::Switchers heaterIdx) { heater.cmdActive = false; } -HeaterHandler::SwitchState HeaterHandler::getSwitchState(heater::Switchers switchNr) const { +HeaterHandler::SwitchState HeaterHandler::getSwitchState(heater::Switch switchNr) const { MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); return heaterVec.at(switchNr).switchState; } -ReturnValue_t HeaterHandler::switchHeater(heater::Switchers heater, SwitchState switchState) { +ReturnValue_t HeaterHandler::switchHeater(heater::Switch heater, SwitchState switchState) { if (switchState == SwitchState::ON) { return sendSwitchCommand(heater, PowerSwitchIF::SWITCH_ON); } else if (switchState == SwitchState::OFF) { @@ -429,7 +429,7 @@ ReturnValue_t HeaterHandler::getSwitchState(uint8_t switchNr) const { if (switchNr > 7) { return returnvalue::FAILED; } - if (getSwitchState(static_cast(switchNr)) == SwitchState::ON) { + if (getSwitchState(static_cast(switchNr)) == SwitchState::ON) { return PowerSwitchIF::SWITCH_ON; } return PowerSwitchIF::SWITCH_OFF; @@ -439,7 +439,7 @@ ReturnValue_t HeaterHandler::getFuseState(uint8_t fuseNr) const { return 0; } uint32_t HeaterHandler::getSwitchDelayMs(void) const { return 2000; } -HasHealthIF::HealthState HeaterHandler::getHealth(heater::Switchers heater) { +HasHealthIF::HealthState HeaterHandler::getHealth(heater::Switch heater) { auto* healthDev = heaterVec.at(heater).healthDevice; if (healthDev != nullptr) { MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); diff --git a/mission/tcs/HeaterHandler.h b/mission/tcs/HeaterHandler.h index 6787b660..402d03f5 100644 --- a/mission/tcs/HeaterHandler.h +++ b/mission/tcs/HeaterHandler.h @@ -20,8 +20,8 @@ #include #include -#include "devices/heaterSwitcherList.h" #include "events/subsystemIdRanges.h" +#include "mission/tcs/defs.h" #include "returnvalues/classIds.h" class PowerSwitchIF; @@ -75,8 +75,8 @@ class HeaterHandler : public ExecutableObjectIF, protected: enum SwitchAction : uint8_t { SET_SWITCH_OFF, SET_SWITCH_ON, NONE }; - ReturnValue_t switchHeater(heater::Switchers heater, SwitchState switchState); - HasHealthIF::HealthState getHealth(heater::Switchers heater); + ReturnValue_t switchHeater(heater::Switch heater, SwitchState switchState); + HasHealthIF::HealthState getHealth(heater::Switch heater); ReturnValue_t performOperation(uint8_t operationCode = 0) override; @@ -174,7 +174,7 @@ class HeaterHandler : public ExecutableObjectIF, * @brief Returns the state of a switch (ON - true, or OFF - false). * @param switchNr The number of the switch to check. */ - SwitchState getSwitchState(heater::Switchers switchNr) const; + SwitchState getSwitchState(heater::Switch switchNr) const; /** * @brief This function runs commands waiting for execution. @@ -198,9 +198,9 @@ class HeaterHandler : public ExecutableObjectIF, const HasModesIF& getModeIF() const override; ModeTreeChildIF& getModeTreeChildIF() override; - void handleSwitchOnCommand(heater::Switchers heaterIdx); + void handleSwitchOnCommand(heater::Switch heaterIdx); - void handleSwitchOffCommand(heater::Switchers heaterIdx); + void handleSwitchOffCommand(heater::Switch heaterIdx); /** * @brief Checks if all switches are off. diff --git a/common/config/devices/heaterSwitcherList.h b/mission/tcs/defs.h similarity index 55% rename from common/config/devices/heaterSwitcherList.h rename to mission/tcs/defs.h index 8f91385d..bab3d862 100644 --- a/common/config/devices/heaterSwitcherList.h +++ b/mission/tcs/defs.h @@ -1,10 +1,10 @@ -#ifndef FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_ -#define FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_ +#ifndef MISSION_TCS_DEFS_H_ +#define MISSION_TCS_DEFS_H_ #include namespace heater { -enum Switchers : uint8_t { +enum Switch : uint8_t { HEATER_0_OBC_BRD, HEATER_1_PLOC_PROC_BRD, HEATER_2_ACS_BRD, @@ -17,4 +17,4 @@ enum Switchers : uint8_t { }; } -#endif /* FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_ */ +#endif /* MISSION_TCS_DEFS_H_ */ From 44325ee1762e24ce389aabf83e8dcccbbdf8fbff Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:15:12 +0200 Subject: [PATCH 02/45] changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 359d8b03..916242b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,16 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +## Changed + +- TCS controller now only has an OFF mode and an ON mode + +## Added + +- TCS controller: SUBMODE_NO_HEATER_CTRL (1) added for ON mode. If this submode is + commanded, all heaters will be switched off and then no further heater + commanding will be done. + # [v1.43.2] 2023-04-05 ## Changed From 19006e79b12668d2655ccd2c09b2ee518a74fc11 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:53:35 +0200 Subject: [PATCH 03/45] better handling for TCS ctrl state --- mission/controller/ThermalController.cpp | 119 ++++++++++++++--------- mission/controller/ThermalController.h | 13 ++- 2 files changed, 82 insertions(+), 50 deletions(-) diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index e06e568d..738b9e14 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -183,6 +183,7 @@ void ThermalController::performControlOperation() { if (allSwitchersOff or transitionWhenHeatersOffCycles == 6) { // Finish the transition transitionWhenHeatersOff = false; + resetThermalStates(); setMode(targetMode, targetSubmode); } else { transitionWhenHeatersOffCycles++; @@ -1571,10 +1572,9 @@ void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { // No sensors available, so switch the heater off. We can not perform control tasks if we // are blind.. if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { - if (submode != SUBMODE_NO_HEATER_CTRL) { - if (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON) { - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); - } + if (heaterCtrlAllowed() and + (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON)) { + heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); } } } @@ -1622,20 +1622,19 @@ bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch re } void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) { + if (not heaterCtrlAllowed()) { + return; + } if (htrCtx.switchState == HeaterHandler::SwitchState::ON) { - if (submode != SUBMODE_NO_HEATER_CTRL) { - sif::info << "TCS: Component " << static_cast(thermalComponent) << " too warm, above " - << whatLimit << ", switching off heater" << std::endl; - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); - heaterStates[htrCtx.switchNr].switchTransition = true; - } + sif::info << "TCS: Component " << static_cast(thermalComponent) << " too warm, above " + << whatLimit << ", switching off heater" << std::endl; + heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent); + heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; } if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == HeaterHandler::SwitchState::ON) { - if (submode != SUBMODE_NO_HEATER_CTRL) { - heaterHandler.switchHeater(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF); - heaterStates[htrCtx.redSwitchNr].switchTransition = true; - } + heaterSwitchHelper(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF, thermalComponent); + heaterStates[htrCtx.redSwitchNr].switchTransition = true; heaterStates[htrCtx.redSwitchNr].target = HeaterHandler::SwitchState::OFF; } } @@ -1649,42 +1648,44 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { if (heaterStates[htrCtx.switchNr].switchTransition) { htrCtx.doHeaterHandling = false; heaterCtrlCheckUpperLimits(htrCtx); - } else { - // Heater off - htrCtx.switchState = heaterHandler.getSwitchState(htrCtx.switchNr); - if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) { - if (sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) { - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::ON); - sif::info << "TCS: Heater " << static_cast(thermalComponent) << " ON" << std::endl; + return; + } + + htrCtx.switchState = heaterHandler.getSwitchState(htrCtx.switchNr); + // Heater off + if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) { + if (sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) { + sif::info << "TCS: Heater " << static_cast(thermalComponent) << " ON" << std::endl; + heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::ON, thermalComponent); + heaterStates[htrCtx.switchNr].switchTransition = true; + heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::ON; + } else { + // Even if heater control is now allowed, we can update the state. + thermalStates[thermalComponent].heating = false; + } + heaterCtrlCheckUpperLimits(htrCtx); + return; + } + + // Heater on + if (htrCtx.switchState == HeaterHandler::SwitchState::ON) { + if (thermalStates[thermalComponent].heating) { + // We are already in a heating cycle, so need to check whether heating task is complete. + if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET and heaterCtrlAllowed()) { + sif::info << "TCS: Heater" << static_cast(thermalComponent) << " OFF" << std::endl; + heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent); heaterStates[htrCtx.switchNr].switchTransition = true; - thermalStates[thermalComponent].heating = true; - heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::ON; - } else { - // Even if heater control is now allowed, we can update the state. - thermalStates[thermalComponent].heating = false; + heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; } - heaterCtrlCheckUpperLimits(htrCtx); - // Heater on - } else if (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON) { - if (thermalStates[thermalComponent].heating) { - // We are already in a heating cycle, so need to check whether heating task is complete. - if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET and heaterCtrlAllowed()) { - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); - sif::info << "TCS: Heater" << static_cast(thermalComponent) << " OFF" << std::endl; - heaterStates[htrCtx.switchNr].switchTransition = true; - heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; - thermalStates[thermalComponent].heating = false; - } - } else { - // This can happen if heater is used as alternative heater (no regular heating cycle), so we - // should still check the upper limits. - bool tooHighHandlerAlreadyCalled = heaterCtrlCheckUpperLimits(htrCtx); - if (sensorTemp >= htrCtx.tempLimit.cutOffLimit) { - componentAboveCutOffLimit = true; - if (not tooHighHandlerAlreadyCalled) { - heaterCtrlTempTooHighHandler(htrCtx, "CutOff-Limit"); - } - } + return; + } + // This can happen if heater is used as alternative heater (no regular heating cycle), so we + // should still check the upper limits. + bool tooHighHandlerAlreadyCalled = heaterCtrlCheckUpperLimits(htrCtx); + if (sensorTemp >= htrCtx.tempLimit.cutOffLimit) { + componentAboveCutOffLimit = true; + if (not tooHighHandlerAlreadyCalled) { + heaterCtrlTempTooHighHandler(htrCtx, "CutOff-Limit"); } } } @@ -1763,6 +1764,28 @@ bool ThermalController::tooHotHandler(object_id_t object, bool& oneShotFlag) { bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO_HEATER_CTRL; } +void ThermalController::resetThermalStates() { + for (auto& thermalState : thermalStates) { + thermalState.heating = false; + } +} + +void ThermalController::heaterSwitchHelper(heater::Switch switchNr, + HeaterHandler::SwitchState state, + unsigned componentIdx) { + timeval currentTime; + Clock::getClockMonotonic(¤tTime); + if (state == HeaterHandler::SwitchState::ON) { + heaterHandler.switchHeater(switchNr, state); + thermalStates[componentIdx].heating = true; + thermalStates[componentIdx].heaterStartTime = currentTime.tv_sec; + } else { + heaterHandler.switchHeater(switchNr, state); + thermalStates[componentIdx].heating = false; + thermalStates[componentIdx].heaterEndTime = currentTime.tv_sec; + } +} + void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag) { // Clear the one shot flag is the component is in acceptable temperature range. if (not tooHotHandler(object, oneShotFlag) and not componentAboveUpperLimit) { diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index 34ffcd49..af27dd29 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -47,8 +47,13 @@ struct TempLimits { struct ThermalState { uint8_t errorCounter; - bool heating; - uint32_t heaterStartTime; + // Is heating on for that thermal module? + bool heating = false; + heater::Switch heaterSwitch = heater::Switch::NUMBER_OF_SWITCHES; + // Heater start time and end times as UNIX seconds. Please note that these times will be updated + // when a switch command is sent, with no guarantess that the heater actually went on. + uint32_t heaterStartTime = 0; + uint32_t heaterEndTime = 0; }; struct HeaterState { @@ -295,6 +300,7 @@ class ThermalController : public ExtendedControllerBase { void startTransition(Mode_t mode, Submode_t submode) override; bool heaterCtrlAllowed() const; + void resetThermalStates(); void resetSensorsArray(); void copySensors(); @@ -309,6 +315,9 @@ class ThermalController : public ExtendedControllerBase { bool chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr); bool selectAndReadSensorTemp(HeaterContext& htrCtx); + void heaterSwitchHelper(heater::Switch switchNr, HeaterHandler::SwitchState state, + unsigned componentIdx); + void ctrlAcsBoard(); void ctrlMgt(); void ctrlRw(); From 3a236a1a3bb095b1f55271f4d03c7f4901575460 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:01:31 +0200 Subject: [PATCH 04/45] all heaters off wrapper --- mission/controller/ThermalController.cpp | 22 +++++++++++++++++----- mission/controller/ThermalController.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 738b9e14..0fe5c862 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1031,7 +1031,7 @@ void ThermalController::ctrlAcsBoard() { if (chooseHeater(switchNr, redSwitchNr)) { if (heaterHandler.getSwitchState(switchNr)) { if (submode != SUBMODE_NO_HEATER_CTRL) { - heaterHandler.switchHeater(switchNr, HeaterHandler::SwitchState::OFF); + heaterSwitchHelper(switchNr, HeaterHandler::SwitchState::OFF, thermalComponent); } } } @@ -1566,6 +1566,7 @@ void ThermalController::performThermalModuleCtrl(const HeaterSwitchStates& heate void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { if (selectAndReadSensorTemp(htrCtx)) { if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { + // Core loop for a thermal component, after sensors and heaters were selected. checkLimitsAndCtrlHeater(htrCtx); } } else { @@ -1574,7 +1575,7 @@ void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { if (heaterCtrlAllowed() and (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON)) { - heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); + heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent); } } } @@ -1786,6 +1787,19 @@ void ThermalController::heaterSwitchHelper(heater::Switch switchNr, } } +void ThermalController::heaterSwitchHelperAllOff() { + timeval currentTime; + Clock::getClockMonotonic(¤tTime); + size_t idx = 0; + for (; idx < heater::Switch::NUMBER_OF_SWITCHES; idx++) { + heaterHandler.switchHeater(static_cast(idx), HeaterHandler::SwitchState::OFF); + } + for (idx = 0; idx < thermalStates.size(); idx++) { + thermalStates[idx].heating = false; + thermalStates[idx].heaterEndTime = currentTime.tv_sec; + } +} + void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag) { // Clear the one shot flag is the component is in acceptable temperature range. if (not tooHotHandler(object, oneShotFlag) and not componentAboveUpperLimit) { @@ -1798,9 +1812,7 @@ void ThermalController::startTransition(Mode_t mode_, Submode_t submode_) { // For MODE_OFF and the no heater control submode, we command all switches to off before // completing the transition. This ensures a consistent state when commanding these modes. if ((mode_ == MODE_OFF) or ((mode_ == MODE_ON) and (submode_ == SUBMODE_NO_HEATER_CTRL))) { - for (uint8_t i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { - heaterHandler.switchHeater(static_cast(i), HeaterHandler::SwitchState::OFF); - } + heaterSwitchHelperAllOff(); transitionWhenHeatersOff = true; targetMode = mode_; targetSubmode = submode_; diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index af27dd29..b47fb8f5 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -315,6 +315,7 @@ class ThermalController : public ExtendedControllerBase { bool chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr); bool selectAndReadSensorTemp(HeaterContext& htrCtx); + void heaterSwitchHelperAllOff(); void heaterSwitchHelper(heater::Switch switchNr, HeaterHandler::SwitchState state, unsigned componentIdx); From 64b4db98ba29f38eb9f526cda73357eb9dfd5d3e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:02:53 +0200 Subject: [PATCH 05/45] i think thats an important bugfix --- mission/controller/ThermalController.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index b47fb8f5..37f59def 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -273,8 +273,8 @@ class ThermalController : public ExtendedControllerBase { Mode_t targetMode = MODE_OFF; Submode_t targetSubmode = SUBMODE_NONE; uint32_t cycles = 0; - std::array thermalStates{}; - std::array heaterStates{}; + std::array thermalStates{}; + std::array heaterStates{}; // Initial delay to make sure all pool variables have been initialized their owners. // Also, wait for system initialization to complete. From c5e18957f5a4b9f9c428e4fe7c8c0bfa30d92f46 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:03:28 +0200 Subject: [PATCH 06/45] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 916242b4..a5989043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ will consitute of a breaking change warranting a new major release: commanded, all heaters will be switched off and then no further heater commanding will be done. +## Fixed + +- Heater states array in TCS controller was too small. + # [v1.43.2] 2023-04-05 ## Changed From 7a53ada4b4ea3040b6470ea3defeb7f0cd1f9dfa Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:09:48 +0200 Subject: [PATCH 07/45] add some more cold test cases --- dummies/TemperatureSensorInserter.cpp | 16 ++++++++++++++++ dummies/TemperatureSensorInserter.h | 2 +- mission/controller/ThermalController.cpp | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dummies/TemperatureSensorInserter.cpp b/dummies/TemperatureSensorInserter.cpp index 11d31779..609ab73b 100644 --- a/dummies/TemperatureSensorInserter.cpp +++ b/dummies/TemperatureSensorInserter.cpp @@ -54,22 +54,38 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { } case (TestCase::COOL_HPA): { if (cycles == 15) { + sif::debug << "Setting cold HPA temperature" << std::endl; max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-60, true); } if (cycles == 30) { + sif::debug << "Setting HPA temperature back to normal" << std::endl; max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(0, true); } break; } case (TestCase::COOL_MGT): { if (cycles == 15) { + sif::debug << "Setting cold MGT temperature" << std::endl; max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(-60, true); } if (cycles == 30) { + sif::debug << "Setting MGT temperature back to normal" << std::endl; max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(0, true); } break; } + case(TestCase::COOL_STR): { + if (cycles == 15) { + sif::debug << "Setting cold STR temperature" << std::endl; + max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(-40, true); + } + if (cycles == 30) { + sif::debug << "Setting STR temperature back to normal" << std::endl; + max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(0, true); + } + break; + + } } cycles++; return returnvalue::OK; diff --git a/dummies/TemperatureSensorInserter.h b/dummies/TemperatureSensorInserter.h index 1727e735..d7d2f1ab 100644 --- a/dummies/TemperatureSensorInserter.h +++ b/dummies/TemperatureSensorInserter.h @@ -24,7 +24,7 @@ class TemperatureSensorInserter : public ExecutableObjectIF, public SystemObject Max31865DummyMap max31865DummyMap; Tmp1075DummyMap tmp1075DummyMap; - enum TestCase { NONE = 0, COOL_SYRLINKS = 1, COOL_HPA = 2, COOL_MGT = 3 }; + enum TestCase { NONE = 0, COOL_SYRLINKS = 1, COOL_HPA = 2, COOL_MGT = 3, COOL_STR = 4 }; int iteration = 0; uint32_t cycles = 0; bool tempsWereInitialized = false; diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 0fe5c862..049e2480 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1718,8 +1718,8 @@ void ThermalController::resetSensorsArray() { } thermalComponent = NONE; } + void ThermalController::heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates) { - // TODO: Test for (unsigned i = 0; i < 7; i++) { if (heaterStates[i].switchTransition) { if (currentHeaterStates[i] == heaterStates[i].target) { From 086dbcc19e8ad572e951f1d41b0e6964861b9d6b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:16:50 +0200 Subject: [PATCH 08/45] some tweaks and fixes --- CMakeLists.txt | 2 +- dummies/TemperatureSensorInserter.cpp | 2 +- dummies/helperFactory.cpp | 7 ++++--- mission/controller/ThermalController.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 784fb9c8..8422f6d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ set(OBSW_ADD_SUS_BOARD_ASS ${INIT_VAL} CACHE STRING "Add sun sensor board assembly") set(OBSW_ADD_THERMAL_TEMP_INSERTER - ${INIT_VAL} + ${OBSW_Q7S_EM} CACHE STRING "Add thermal sensor temperature inserter") set(OBSW_ADD_ACS_BOARD ${INIT_VAL} diff --git a/dummies/TemperatureSensorInserter.cpp b/dummies/TemperatureSensorInserter.cpp index 609ab73b..057f1704 100644 --- a/dummies/TemperatureSensorInserter.cpp +++ b/dummies/TemperatureSensorInserter.cpp @@ -15,7 +15,7 @@ TemperatureSensorInserter::TemperatureSensorInserter(object_id_t objectId, tmp1075DummyMap(std::move(tempTmpSensorDummies_)) {} ReturnValue_t TemperatureSensorInserter::initialize() { - testCase = TestCase::COOL_MGT; + testCase = TestCase::COOL_STR; return returnvalue::OK; } diff --git a/dummies/helperFactory.cpp b/dummies/helperFactory.cpp index 404b640c..6d29b47f 100644 --- a/dummies/helperFactory.cpp +++ b/dummies/helperFactory.cpp @@ -193,9 +193,10 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio tmpSensorDummies.emplace( objects::TMP1075_HANDLER_PLPCDU_0, new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_0, objects::DUMMY_COM_IF, comCookieDummy)); - tmpSensorDummies.emplace( - objects::TMP1075_HANDLER_PLPCDU_1, - new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF, comCookieDummy)); + // damaged. +// tmpSensorDummies.emplace( +// objects::TMP1075_HANDLER_PLPCDU_1, +// new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF, comCookieDummy)); tmpSensorDummies.emplace( objects::TMP1075_HANDLER_IF_BOARD, new Tmp1075Dummy(objects::TMP1075_HANDLER_IF_BOARD, objects::DUMMY_COM_IF, comCookieDummy)); diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 049e2480..914b3d26 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1673,7 +1673,7 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { if (thermalStates[thermalComponent].heating) { // We are already in a heating cycle, so need to check whether heating task is complete. if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET and heaterCtrlAllowed()) { - sif::info << "TCS: Heater" << static_cast(thermalComponent) << " OFF" << std::endl; + sif::info << "TCS: Heater " << static_cast(thermalComponent) << " OFF" << std::endl; heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent); heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; From d7dc3f34c7aacd32a6e066d74f12336f8bce804b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:24:16 +0200 Subject: [PATCH 09/45] consecutive cold test --- bsp_q7s/OBSWConfig.h.in | 2 ++ dummies/TemperatureSensorInserter.cpp | 22 ++++++++++++++++------ dummies/TemperatureSensorInserter.h | 9 ++++++++- dummies/helperFactory.cpp | 7 ++++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/bsp_q7s/OBSWConfig.h.in b/bsp_q7s/OBSWConfig.h.in index b60472d6..3502a7bb 100644 --- a/bsp_q7s/OBSWConfig.h.in +++ b/bsp_q7s/OBSWConfig.h.in @@ -43,7 +43,9 @@ #define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@ #define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@ #define OBSW_ADD_CCSDS_IP_CORES @OBSW_ADD_CCSDS_IP_CORES@ +// Only relevant for EM for TCS tests. #define OBSW_ADD_THERMAL_TEMP_INSERTER @OBSW_ADD_THERMAL_TEMP_INSERTER@ + // Set to 1 if all telemetry should be sent to the PTME IP Core #define OBSW_TM_TO_PTME @OBSW_TM_TO_PTME@ // Set to 1 if telecommands are received via the PDEC IP Core diff --git a/dummies/TemperatureSensorInserter.cpp b/dummies/TemperatureSensorInserter.cpp index 057f1704..b6f46fb8 100644 --- a/dummies/TemperatureSensorInserter.cpp +++ b/dummies/TemperatureSensorInserter.cpp @@ -15,7 +15,7 @@ TemperatureSensorInserter::TemperatureSensorInserter(object_id_t objectId, tmp1075DummyMap(std::move(tempTmpSensorDummies_)) {} ReturnValue_t TemperatureSensorInserter::initialize() { - testCase = TestCase::COOL_STR; + testCase = TestCase::COLD_STR_CONSECUTIVE; return returnvalue::OK; } @@ -35,7 +35,7 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { case (TestCase::NONE): { break; } - case (TestCase::COOL_SYRLINKS): { + case (TestCase::COLD_SYRLINKS): { // TODO: How do I insert this? // Does not work on EM, where a real syrlinks device is connected. if (cycles == 15) { @@ -52,7 +52,7 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { } break; } - case (TestCase::COOL_HPA): { + case (TestCase::COLD_HPA): { if (cycles == 15) { sif::debug << "Setting cold HPA temperature" << std::endl; max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-60, true); @@ -63,7 +63,7 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { } break; } - case (TestCase::COOL_MGT): { + case (TestCase::COLD_MGT): { if (cycles == 15) { sif::debug << "Setting cold MGT temperature" << std::endl; max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(-60, true); @@ -74,7 +74,8 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { } break; } - case(TestCase::COOL_STR): { + case (TestCase::COLD_STR): + case (TestCase::COLD_STR_CONSECUTIVE): { if (cycles == 15) { sif::debug << "Setting cold STR temperature" << std::endl; max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(-40, true); @@ -83,8 +84,17 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) { sif::debug << "Setting STR temperature back to normal" << std::endl; max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(0, true); } + if (testCase == TestCase::COLD_STR_CONSECUTIVE) { + if (cycles == 45) { + sif::debug << "Setting cold STR temperature again" << std::endl; + max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(-40, true); + } + if (cycles == 60) { + sif::debug << "Setting STR temperature back to normal again" << std::endl; + max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(0, true); + } + } break; - } } cycles++; diff --git a/dummies/TemperatureSensorInserter.h b/dummies/TemperatureSensorInserter.h index d7d2f1ab..675bcd91 100644 --- a/dummies/TemperatureSensorInserter.h +++ b/dummies/TemperatureSensorInserter.h @@ -24,7 +24,14 @@ class TemperatureSensorInserter : public ExecutableObjectIF, public SystemObject Max31865DummyMap max31865DummyMap; Tmp1075DummyMap tmp1075DummyMap; - enum TestCase { NONE = 0, COOL_SYRLINKS = 1, COOL_HPA = 2, COOL_MGT = 3, COOL_STR = 4 }; + enum TestCase { + NONE = 0, + COLD_SYRLINKS = 1, + COLD_HPA = 2, + COLD_MGT = 3, + COLD_STR = 4, + COLD_STR_CONSECUTIVE = 5, + }; int iteration = 0; uint32_t cycles = 0; bool tempsWereInitialized = false; diff --git a/dummies/helperFactory.cpp b/dummies/helperFactory.cpp index 6d29b47f..54ca3e89 100644 --- a/dummies/helperFactory.cpp +++ b/dummies/helperFactory.cpp @@ -194,9 +194,10 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio objects::TMP1075_HANDLER_PLPCDU_0, new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_0, objects::DUMMY_COM_IF, comCookieDummy)); // damaged. -// tmpSensorDummies.emplace( -// objects::TMP1075_HANDLER_PLPCDU_1, -// new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF, comCookieDummy)); + // tmpSensorDummies.emplace( + // objects::TMP1075_HANDLER_PLPCDU_1, + // new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF, + // comCookieDummy)); tmpSensorDummies.emplace( objects::TMP1075_HANDLER_IF_BOARD, new Tmp1075Dummy(objects::TMP1075_HANDLER_IF_BOARD, objects::DUMMY_COM_IF, comCookieDummy)); From 4acf66a020eecb99c51a406e3f09d7bb461ff62d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 15:31:32 +0200 Subject: [PATCH 10/45] fix unittest --- mission/controller/ThermalController.cpp | 2 +- unittest/controller/testThermalController.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 914b3d26..74581166 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -17,7 +17,7 @@ #include // Enabling this should trigger a special event which in turn should trigger a system reaction. -#define LOWER_SYRLINKS_UPPER_LIMITS 0 +#define LOWER_SYRLINKS_UPPER_LIMITS 1 #define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_PLOC_UPPER_LIMITS 0 diff --git a/unittest/controller/testThermalController.cpp b/unittest/controller/testThermalController.cpp index 623c6d52..5ee41ce2 100644 --- a/unittest/controller/testThermalController.cpp +++ b/unittest/controller/testThermalController.cpp @@ -47,7 +47,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { CommandMessage modeMessage; ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, - ControllerBase::MODE_NORMAL, HasModesIF::SUBMODE_NONE); + HasModesIF::MODE_ON, HasModesIF::SUBMODE_NONE); MessageQueueIF* commandQueue = QueueFactory::instance()->createMessageQueue(5, MessageQueueMessage::MAX_MESSAGE_SIZE); @@ -57,7 +57,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { REQUIRE(controller.performOperation(0) == returnvalue::OK); REQUIRE(testEnvironment::eventManager->isEventInEventList( - THERMAL_CONTROLLER_ID, HasModesIF::MODE_INFO, ControllerBase::MODE_NORMAL, + THERMAL_CONTROLLER_ID, HasModesIF::MODE_INFO, HasModesIF::MODE_ON, HasModesIF::SUBMODE_NONE) == true); QueueFactory::instance()->deleteMessageQueue(commandQueue); From b816b386cf88ecf997ccf6330bd9d503b5a1bbd9 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 16:47:56 +0200 Subject: [PATCH 11/45] bump fsfw --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 285d327b..894d1e3b 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 285d327b97514946f0714e477289f67ee8bd413f +Subproject commit 894d1e3b8744bb59b498e8ac56f19065759af366 From 0a84eab0ef911d8add756190e7bb862e8d434b61 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 16:51:49 +0200 Subject: [PATCH 12/45] move cfdp handler --- mission/cfdp/CMakeLists.txt | 2 + mission/cfdp/CfdpHandler.cpp | 134 +++++++++++++++++++++++++++++++++++ mission/cfdp/CfdpHandler.h | 71 +++++++++++++++++++ mission/genericFactory.cpp | 2 +- 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 mission/cfdp/CfdpHandler.cpp create mode 100644 mission/cfdp/CfdpHandler.h diff --git a/mission/cfdp/CMakeLists.txt b/mission/cfdp/CMakeLists.txt index 8b137891..97d7142b 100644 --- a/mission/cfdp/CMakeLists.txt +++ b/mission/cfdp/CMakeLists.txt @@ -1 +1,3 @@ +target_sources( + ${LIB_EIVE_MISSION} PRIVATE CfdpHandler.cpp) diff --git a/mission/cfdp/CfdpHandler.cpp b/mission/cfdp/CfdpHandler.cpp new file mode 100644 index 00000000..902097b6 --- /dev/null +++ b/mission/cfdp/CfdpHandler.cpp @@ -0,0 +1,134 @@ +#include "CfdpHandler.h" + +#include "fsfw/cfdp/pdu/AckPduReader.h" +#include "fsfw/cfdp/pdu/PduHeaderReader.h" +#include "fsfw/globalfunctions/arrayprinter.h" +#include "fsfw/ipc/QueueFactory.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +using namespace returnvalue; +using namespace cfdp; + +CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg) + : SystemObject(fsfwParams.objectId), + msgQueue(fsfwParams.msgQueue), + destHandler( + DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler), + cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList, + cfdpCfg.lostSegmentsList), + FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore, + fsfwParams.tmStore)) { + destHandler.setMsgQueue(msgQueue); +} + +[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; } + +[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const { + return destHandler.getDestHandlerParams().cfg.localId.getValue(); +} + +[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); } + +ReturnValue_t CfdpHandler::initialize() { + ReturnValue_t result = destHandler.initialize(); + if (result != OK) { + return result; + } + tcStore = destHandler.getTcStore(); + tmStore = destHandler.getTmStore(); + + return SystemObject::initialize(); +} + +ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) { + // TODO: Receive TC packets and route them to source and dest handler, depending on which is + // correct or more appropriate + ReturnValue_t status; + ReturnValue_t result = OK; + TmTcMessage tmtcMsg; + for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK; + status = msgQueue.receiveMessage(&tmtcMsg)) { + result = handleCfdpPacket(tmtcMsg); + if (result != OK) { + status = result; + } + } + auto& fsmRes = destHandler.performStateMachine(); + // TODO: Error handling? + while (fsmRes.callStatus == CallStatus::CALL_AGAIN) { + destHandler.performStateMachine(); + // TODO: Error handling? + } + return status; +} + +ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) { + auto accessorPair = tcStore->getData(msg.getStorageId()); + if (accessorPair.first != OK) { + return accessorPair.first; + } + PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size()); + ReturnValue_t result = reader.parseData(); + if (result != returnvalue::OK) { + return INVALID_PDU_FORMAT; + } + // The CFDP distributor should have taken care of ensuring the destination ID is correct + PduType type = reader.getPduType(); + // Only the destination handler can process these PDUs + if (type == PduType::FILE_DATA) { + // Disable auto-deletion of packet + accessorPair.second.release(); + PacketInfo info(type, msg.getStorageId()); + result = destHandler.passPacket(info); + } else { + // Route depending on PDU type and directive type if applicable. It retrieves directive type + // from the raw stream for better performance (with sanity and directive code check). + // The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding + // procedure. + + // PDU header only. Invalid supplied data. A directive packet should have a valid data field + // with at least one byte being the directive code + const uint8_t* pduDataField = reader.getPduDataField(); + if (pduDataField == nullptr) { + return INVALID_PDU_FORMAT; + } + if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) { + return INVALID_DIRECTIVE_FIELD; + } + auto directive = static_cast(pduDataField[0]); + + auto passToDestHandler = [&]() { + accessorPair.second.release(); + PacketInfo info(type, msg.getStorageId(), directive); + result = destHandler.passPacket(info); + }; + auto passToSourceHandler = [&]() { + + }; + if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or + directive == FileDirective::PROMPT) { + // Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a. + // the destination handler + passToDestHandler(); + } else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or + directive == FileDirective::KEEP_ALIVE) { + // Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a. + // the source handler + passToSourceHandler(); + } else if (directive == FileDirective::ACK) { + // Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply + // extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to + // the source handler, for a Finished PDU, it is passed to the destination handler. + FileDirective ackedDirective; + if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) { + return INVALID_ACK_DIRECTIVE_FIELDS; + } + if (ackedDirective == FileDirective::EOF_DIRECTIVE) { + passToSourceHandler(); + } else if (ackedDirective == FileDirective::FINISH) { + passToDestHandler(); + } + } + } + return result; +} diff --git a/mission/cfdp/CfdpHandler.h b/mission/cfdp/CfdpHandler.h new file mode 100644 index 00000000..2de9f7dd --- /dev/null +++ b/mission/cfdp/CfdpHandler.h @@ -0,0 +1,71 @@ +#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H +#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H + +#include + +#include "fsfw/cfdp/handler/DestHandler.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h" +#include "fsfw/tmtcservices/TmTcMessage.h" + +struct FsfwHandlerParams { + FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest, + StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue) + : objectId(objectId), + vfs(vfs), + packetDest(packetDest), + tcStore(tcStore), + tmStore(tmStore), + msgQueue(msgQueue) {} + object_id_t objectId{}; + HasFileSystemIF& vfs; + AcceptsTelemetryIF& packetDest; + StorageManagerIF& tcStore; + StorageManagerIF& tmStore; + MessageQueueIF& msgQueue; +}; + +struct CfdpHandlerCfg { + CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg, + cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler, + cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList, + cfdp::RemoteConfigTableIF& remoteCfgProvider) + : id(std::move(localId)), + indicCfg(indicationCfg), + packetInfoList(packetInfo), + lostSegmentsList(lostSegmentsList), + remoteCfgProvider(remoteCfgProvider), + userHandler(userHandler), + faultHandler(userFaultHandler) {} + + cfdp::EntityId id; + cfdp::IndicationCfg indicCfg; + cfdp::PacketInfoListBase& packetInfoList; + cfdp::LostSegmentsListBase& lostSegmentsList; + cfdp::RemoteConfigTableIF& remoteCfgProvider; + cfdp::UserBase& userHandler; + cfdp::FaultHandlerBase& faultHandler; +}; + +class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF { + public: + explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg); + + [[nodiscard]] const char* getName() const override; + [[nodiscard]] uint32_t getIdentifier() const override; + [[nodiscard]] MessageQueueId_t getRequestQueue() const override; + + ReturnValue_t initialize() override; + ReturnValue_t performOperation(uint8_t operationCode) override; + + private: + MessageQueueIF& msgQueue; + cfdp::DestHandler destHandler; + StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; + + ReturnValue_t handleCfdpPacket(TmTcMessage& msg); +}; + +#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H diff --git a/mission/genericFactory.cpp b/mission/genericFactory.cpp index ce338097..6ce0b7c0 100644 --- a/mission/genericFactory.cpp +++ b/mission/genericFactory.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include From 7869289abcffb6040b8947845aecae9ad83826d2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 16:53:07 +0200 Subject: [PATCH 13/45] bump fsfw --- fsfw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fsfw b/fsfw index 894d1e3b..ffa2fa47 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit 894d1e3b8744bb59b498e8ac56f19065759af366 +Subproject commit ffa2fa477f105cc876264335d5b25fc9b174a181 From d42b6798e0f5de706de75686d48fb44def65d0da Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 17:29:32 +0200 Subject: [PATCH 14/45] better reply result handling --- CHANGELOG.md | 1 + linux/acs/AcsBoardPolling.cpp | 20 ++++++++++++++++---- linux/acs/SusPolling.cpp | 4 ++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc5bfc7b..57d12f2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ will consitute of a breaking change warranting a new major release: SD card switch from 0 to 1 and vice-versa works without errors from persistent TM stores now. - Add a way for the SUS polling to detect broken or off devices by checking the retrieved temperature for the all-ones value (0x0fff). +- Better reply result handling for the ACS board devices. ## Changed diff --git a/linux/acs/AcsBoardPolling.cpp b/linux/acs/AcsBoardPolling.cpp index b289ef70..175bd693 100644 --- a/linux/acs/AcsBoardPolling.cpp +++ b/linux/acs/AcsBoardPolling.cpp @@ -127,6 +127,7 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send adis.ownReply.cfgWasSet = false; adis.ownReply.dataWasSet = false; } + adis.replyResult = returnvalue::FAILED; adis.mode = req->mode; } return returnvalue::OK; @@ -145,6 +146,7 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send } else { gyro.ownReply.cfgWasSet = false; } + gyro.replyResult = returnvalue::FAILED; gyro.mode = req->mode; } return returnvalue::OK; @@ -163,6 +165,7 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send mgm.ownReply.dataWasSet = false; mgm.ownReply.temperatureWasSet = false; } + mgm.replyResult = returnvalue::FAILED; mgm.mode = req->mode; } return returnvalue::OK; @@ -180,6 +183,7 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send } else { mgm.ownReply.dataWasRead = false; } + mgm.replyResult = returnvalue::FAILED; mgm.mode = req->mode; } return returnvalue::OK; @@ -309,18 +313,18 @@ void AcsBoardPolling::gyroL3gHandler(GyroL3g& l3g) { std::memcpy(cmdBuf.data() + 1, l3g.sensorCfg, 5); result = spiComIF.sendMessage(l3g.cookie, cmdBuf.data(), 6); if (result != returnvalue::OK) { - l3g.replyResult = returnvalue::OK; + l3g.replyResult = result; } // Ignore useless reply and red config cmdBuf[0] = l3gd20h::CTRL_REG_1 | l3gd20h::AUTO_INCREMENT_MASK | l3gd20h::READ_MASK; std::memset(cmdBuf.data() + 1, 0, 5); result = spiComIF.sendMessage(l3g.cookie, cmdBuf.data(), 6); if (result != returnvalue::OK) { - l3g.replyResult = returnvalue::OK; + l3g.replyResult = result; } result = spiComIF.readReceivedMessage(l3g.cookie, &rawReply, &dummy); if (result != returnvalue::OK) { - l3g.replyResult = returnvalue::OK; + l3g.replyResult = result; } MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); // Cross check configuration as verification that communication is working @@ -331,6 +335,7 @@ void AcsBoardPolling::gyroL3gHandler(GyroL3g& l3g) { return; } } + l3g.replyResult = returnvalue::OK; l3g.performStartup = false; l3g.ownReply.cfgWasSet = true; l3g.ownReply.sensitivity = l3gd20h::ctrlReg4ToSensitivity(l3g.sensorCfg[3]); @@ -357,6 +362,7 @@ void AcsBoardPolling::gyroL3gHandler(GyroL3g& l3g) { return; } } + l3g.replyResult = returnvalue::OK; l3g.ownReply.statusReg = rawReply[l3gd20h::STATUS_IDX]; l3g.ownReply.angVelocities[0] = (rawReply[l3gd20h::OUT_X_H] << 8) | rawReply[l3gd20h::OUT_X_L]; l3g.ownReply.angVelocities[1] = (rawReply[l3gd20h::OUT_Y_H] << 8) | rawReply[l3gd20h::OUT_Y_L]; @@ -495,6 +501,7 @@ void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) { gyro.ownReply.cfg.prodId = prodId; gyro.ownReply.data.sensitivity = adis1650x::rangMdlToSensitivity(gyro.ownReply.cfg.rangMdl); gyro.performStartup = false; + gyro.replyResult = returnvalue::OK; } // Read regular registers std::memcpy(cmdBuf.data(), adis1650x::BURST_READ_ENABLE.data(), @@ -533,6 +540,7 @@ void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) { } MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); + gyro.replyResult = returnvalue::OK; gyro.ownReply.dataWasSet = true; gyro.ownReply.cfg.diagStat = rawReply[2] << 8 | rawReply[3]; gyro.ownReply.data.angVelocities[0] = (rawReply[4] << 8) | rawReply[5]; @@ -590,6 +598,7 @@ void AcsBoardPolling::mgmLis3Handler(MgmLis3& mgm) { } // Done here. We can always read back config and data during periodic handling mgm.performStartup = false; + mgm.replyResult = returnvalue::OK; } cmdBuf[0] = mgmLis3::readCommand(mgmLis3::CTRL_REG1, true); std::memset(cmdBuf.data() + 1, 0, mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS); @@ -607,7 +616,7 @@ void AcsBoardPolling::mgmLis3Handler(MgmLis3& mgm) { // Verify communication by re-checking config if (rawReply[1] != mgm.cfg[0] or rawReply[2] != mgm.cfg[1] or rawReply[3] != mgm.cfg[2] or rawReply[4] != mgm.cfg[3] or rawReply[5] != mgm.cfg[4]) { - mgm.replyResult = result; + mgm.replyResult = returnvalue::FAILED; return; } { @@ -634,6 +643,7 @@ void AcsBoardPolling::mgmLis3Handler(MgmLis3& mgm) { return; } MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); + mgm.replyResult = returnvalue::OK; mgm.ownReply.temperatureWasSet = true; mgm.ownReply.temperatureRaw = (rawReply[2] << 8) | rawReply[1]; } @@ -704,6 +714,7 @@ void AcsBoardPolling::mgmRm3100Handler(MgmRm3100& mgm) { return; } mgm.performStartup = false; + mgm.replyResult = returnvalue::OK; } // Regular read operation cmdBuf[0] = mgmRm3100::MEASUREMENT_REG_START | mgmRm3100::READ_MASK; @@ -725,6 +736,7 @@ void AcsBoardPolling::mgmRm3100Handler(MgmRm3100& mgm) { mgm.ownReply.scaleFactors[idx] = 1.0 / mgmRm3100::DEFAULT_GAIN; } mgm.ownReply.dataWasRead = true; + mgm.replyResult = returnvalue::OK; // Bitshift trickery to account for 24 bit signed value. mgm.ownReply.mgmValuesRaw[0] = ((rawReply[1] << 24) | (rawReply[2] << 16) | (rawReply[3] << 8)) >> 8; diff --git a/linux/acs/SusPolling.cpp b/linux/acs/SusPolling.cpp index 0e09b02a..1da5ef5e 100644 --- a/linux/acs/SusPolling.cpp +++ b/linux/acs/SusPolling.cpp @@ -96,7 +96,7 @@ ReturnValue_t SusPolling::readReceivedMessage(CookieIF* cookie, uint8_t** buffer if (susIdx < 0) { return FAILED; } - if(susDevs[susIdx].replyResult != returnvalue::OK) { + if (susDevs[susIdx].replyResult != returnvalue::OK) { return susDevs[susIdx].replyResult; } MutexGuard mg(ipcLock); @@ -170,7 +170,7 @@ ReturnValue_t SusPolling::handleSusPolling() { susDevs[idx].ownReply.tempRaw = ((rawReply[0] & 0x0f) << 8) | rawReply[1]; // Reply is all ones. Sensor is probably off or faulty when // it should not be. - if(susDevs[idx].ownReply.tempRaw == 0x0fff) { + if (susDevs[idx].ownReply.tempRaw == 0x0fff) { susDevs[idx].replyResult = returnvalue::FAILED; } else { susDevs[idx].replyResult = returnvalue::OK; From 776a53b2437abc545a5685826bf874b58fd66ddb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 18:03:07 +0200 Subject: [PATCH 15/45] dont send anything in break CD --- mission/acs/GyrAdis1650XHandler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mission/acs/GyrAdis1650XHandler.cpp b/mission/acs/GyrAdis1650XHandler.cpp index 57033e80..147b9e57 100644 --- a/mission/acs/GyrAdis1650XHandler.cpp +++ b/mission/acs/GyrAdis1650XHandler.cpp @@ -56,6 +56,9 @@ ReturnValue_t GyrAdis1650XHandler::buildNormalDeviceCommand(DeviceCommandId_t *i ReturnValue_t GyrAdis1650XHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { switch (internalState) { case (InternalState::STARTUP): { + if(breakCountdown.isBusy()) { + return NOTHING_TO_SEND; + } *id = adis1650x::REQUEST; return preparePeriodicRequest(acs::SimpleSensorMode::NORMAL); } From 7c36660000cd974909ff674cdedb085730b0a676 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 18:15:12 +0200 Subject: [PATCH 16/45] that was nasty --- linux/acs/AcsBoardPolling.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/linux/acs/AcsBoardPolling.cpp b/linux/acs/AcsBoardPolling.cpp index 175bd693..938d0e15 100644 --- a/linux/acs/AcsBoardPolling.cpp +++ b/linux/acs/AcsBoardPolling.cpp @@ -31,7 +31,7 @@ ReturnValue_t AcsBoardPolling::performOperation(uint8_t operationCode) { ipcLock->unlockMutex(); semaphore->acquire(); // Give all tasks or the PST some time to submit all consecutive requests. - TaskFactory::delayTask(2); + TaskFactory::delayTask(3); { // Measured to take 0-1 ms in debug build. // Stopwatch watch; @@ -113,7 +113,8 @@ ReturnValue_t AcsBoardPolling::sendMessage(CookieIF* cookie, const uint8_t* send if (req->mode != adis.mode) { if (req->mode == acs::SimpleSensorMode::NORMAL) { adis.type = req->type; - adis.countdown.setTimeout(adis1650x::START_UP_TIME); + // The initial countdown is handled by the device handler now. + // adis.countdown.setTimeout(adis1650x::START_UP_TIME); if (adis.type == adis1650x::Type::ADIS16507) { adis.ownReply.data.accelScaling = adis1650x::ACCELEROMETER_RANGE_16507; } else if (adis.type == adis1650x::Type::ADIS16505) { @@ -449,20 +450,15 @@ ReturnValue_t AcsBoardPolling::readAdisCfg(SpiCookie& cookie, size_t transferLen void AcsBoardPolling::gyroAdisHandler(GyroAdis& gyro) { ReturnValue_t result; acs::SimpleSensorMode mode = acs::SimpleSensorMode::OFF; - bool cdHasTimedOut = false; bool mustPerformStartup = false; { MutexGuard mg(ipcLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); mode = gyro.mode; - cdHasTimedOut = gyro.countdown.hasTimedOut(); mustPerformStartup = gyro.performStartup; } if (mode == acs::SimpleSensorMode::OFF) { return; } - if (not cdHasTimedOut) { - return; - } if (mustPerformStartup) { uint8_t regList[6]; // Read configuration From 5925de94e73ec215c930e4b08780f81339750e42 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 18:16:58 +0200 Subject: [PATCH 17/45] changelog --- CHANGELOG.md | 1 + mission/acs/GyrAdis1650XHandler.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d12f2c..857cd052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ will consitute of a breaking change warranting a new major release: - Add a way for the SUS polling to detect broken or off devices by checking the retrieved 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 now. ## Changed diff --git a/mission/acs/GyrAdis1650XHandler.cpp b/mission/acs/GyrAdis1650XHandler.cpp index 147b9e57..b9e0b049 100644 --- a/mission/acs/GyrAdis1650XHandler.cpp +++ b/mission/acs/GyrAdis1650XHandler.cpp @@ -56,7 +56,7 @@ ReturnValue_t GyrAdis1650XHandler::buildNormalDeviceCommand(DeviceCommandId_t *i ReturnValue_t GyrAdis1650XHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { switch (internalState) { case (InternalState::STARTUP): { - if(breakCountdown.isBusy()) { + if (breakCountdown.isBusy()) { return NOTHING_TO_SEND; } *id = adis1650x::REQUEST; From ff28b628a420d9b24653419e171a0a1958f5a405 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 18:17:30 +0200 Subject: [PATCH 18/45] leave that value --- linux/acs/AcsBoardPolling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux/acs/AcsBoardPolling.cpp b/linux/acs/AcsBoardPolling.cpp index 938d0e15..bc3dff74 100644 --- a/linux/acs/AcsBoardPolling.cpp +++ b/linux/acs/AcsBoardPolling.cpp @@ -31,7 +31,7 @@ ReturnValue_t AcsBoardPolling::performOperation(uint8_t operationCode) { ipcLock->unlockMutex(); semaphore->acquire(); // Give all tasks or the PST some time to submit all consecutive requests. - TaskFactory::delayTask(3); + TaskFactory::delayTask(2); { // Measured to take 0-1 ms in debug build. // Stopwatch watch; From b3f5e7460935d4c1890f7d22226dd2377120bb08 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 18:18:33 +0200 Subject: [PATCH 19/45] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 857cd052..9956115d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ will consitute of a breaking change warranting a new major release: - Add a way for the SUS polling to detect broken or off devices by checking the retrieved 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 now. +- ADIS1650X initial timeout handling now performed in device handler. ## Changed From c9cc1d4cfeb9bbec110ff7181279de6bf6aad8cb Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Tue, 11 Apr 2023 22:58:13 +0200 Subject: [PATCH 20/45] done --- CHANGELOG.md | 4 + dummies/helperFactory.cpp | 4 +- linux/ObjectFactory.cpp | 4 +- mission/controller/ThermalController.cpp | 18 ++-- mission/controller/ThermalController.h | 8 +- mission/genericFactory.cpp | 14 +++- mission/genericFactory.h | 3 +- mission/power/defs.h | 1 + mission/system/CMakeLists.txt | 5 +- mission/system/SharedPowerAssemblyBase.cpp | 91 +++++++++++++++++++++ mission/system/SharedPowerAssemblyBase.h | 27 ++++++ mission/system/acs/DualLaneAssemblyBase.h | 7 +- mission/system/acs/RwAssembly.cpp | 52 +----------- mission/system/acs/RwAssembly.h | 11 +-- mission/system/fdir/RtdFdir.cpp | 2 +- mission/system/objects/TcsBoardAssembly.cpp | 67 +++------------ mission/system/objects/TcsBoardAssembly.h | 20 ++--- mission/tcs/defs.h | 9 ++ tmtc | 2 +- 19 files changed, 200 insertions(+), 149 deletions(-) create mode 100644 mission/system/SharedPowerAssemblyBase.cpp create mode 100644 mission/system/SharedPowerAssemblyBase.h create mode 100644 mission/tcs/defs.h 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 From df7236cfee88c58a2426aef106e12bc6498fc30a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 00:25:21 +0200 Subject: [PATCH 21/45] fix untitest --- unittest/controller/testThermalController.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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); From f4c156479aab9e703e34b90901197559e6d8ae11 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 13:26:23 +0200 Subject: [PATCH 22/45] prep v1.44.1 --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 2 +- tmtc | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be62180f..7a5953f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +# [v1.44.1] 2023-04-12 + +- eive-tmtc: v2.22.1 + ## Fixed - Bugfixes and improvements for SDC state machine. Internal state was not updated correctly due diff --git a/CMakeLists.txt b/CMakeLists.txt index 7989ff35..6d73475d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ cmake_minimum_required(VERSION 3.13) set(OBSW_VERSION_MAJOR 1) set(OBSW_VERSION_MINOR 44) -set(OBSW_VERSION_REVISION 0) +set(OBSW_VERSION_REVISION 1) # set(CMAKE_VERBOSE TRUE) diff --git a/tmtc b/tmtc index f075d289..01b3a894 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit f075d28905b42a018b275d8c640cb0fd9d64dc26 +Subproject commit 01b3a894e66e7f38dd2e7a35e329e99a6199b7f1 From 0e6f222ef17a5b961b8ddb87aea770183ec45a28 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 13:40:21 +0200 Subject: [PATCH 23/45] update intall-obsw-yocto.sh --- scripts/install-obsw-yocto.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install-obsw-yocto.sh b/scripts/install-obsw-yocto.sh index 08fb78d3..ae6fbee7 100755 --- a/scripts/install-obsw-yocto.sh +++ b/scripts/install-obsw-yocto.sh @@ -11,7 +11,7 @@ fi init_dir=$(pwd) obsw_root="" -q7s_yocto_dir="q7s-yocto" +q7s_yocto_dir="yocto" q7s_package_path="q7s-package/${q7s_yocto_dir}" obsw_version_filename="obsw_version.txt" From 3ba81d19a71ce55d7ccc1033758c187ae3254a63 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 13:40:59 +0200 Subject: [PATCH 24/45] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a5953f3..5bbbbabc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +## Fixed + +- Small fix for `install-obsw-yocto.sh` script + # [v1.44.1] 2023-04-12 - eive-tmtc: v2.22.1 From 28080794440512d8cc0c9a1e0cae5b40048afd05 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 16:29:34 +0200 Subject: [PATCH 25/45] add q7s-package update in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bbbbabc..b3ba713b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ will consitute of a breaking change warranting a new major release: # [unreleased] +- q7s-package: v2.5.0 + ## Fixed - Small fix for `install-obsw-yocto.sh` script From e063a7148acd26e8700f841a265a06863bb6cac7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 17:23:08 +0200 Subject: [PATCH 26/45] this snippet should recognize faulty sensors --- mission/cfdp/CMakeLists.txt | 4 +--- mission/genericFactory.cpp | 2 +- mission/tcs/Max31865EiveHandler.cpp | 11 +++++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mission/cfdp/CMakeLists.txt b/mission/cfdp/CMakeLists.txt index 97d7142b..71d62ce8 100644 --- a/mission/cfdp/CMakeLists.txt +++ b/mission/cfdp/CMakeLists.txt @@ -1,3 +1 @@ - -target_sources( - ${LIB_EIVE_MISSION} PRIVATE CfdpHandler.cpp) +target_sources(${LIB_EIVE_MISSION} PRIVATE CfdpHandler.cpp) diff --git a/mission/genericFactory.cpp b/mission/genericFactory.cpp index cbef2f77..9889fe9e 100644 --- a/mission/genericFactory.cpp +++ b/mission/genericFactory.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/mission/tcs/Max31865EiveHandler.cpp b/mission/tcs/Max31865EiveHandler.cpp index 284a2d0c..599071ef 100644 --- a/mission/tcs/Max31865EiveHandler.cpp +++ b/mission/tcs/Max31865EiveHandler.cpp @@ -1,6 +1,8 @@ #include #include +#include "fsfw/thermal/tcsDefinitions.h" + Max31865EiveHandler::Max31865EiveHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie) : DeviceHandlerBase(objectId, comIF, comCookie, nullptr), @@ -152,6 +154,15 @@ ReturnValue_t Max31865EiveHandler::interpretDeviceReply(DeviceCommandId_t id, transitionOk = true; return returnvalue::OK; } + // If the 15 received bits are all ones, this is considered a case where the device does not + // work because it does not drive the MISO line. This can happens if the sensor is broken + // or off. + if (exchangeStruct.adcCode == 0x7fff) { + PoolReadGuard pg(&sensorDataset); + sensorDataset.temperatureCelcius.setValid(false); + sensorDataset.temperatureCelcius = thermal::INVALID_TEMPERATURE; + return returnvalue::FAILED; + } // Calculate resistance float rtdValue = exchangeStruct.adcCode * EiveMax31855::RTD_RREF_PT1000 / INT16_MAX; From ae80eac9a24a2216dacfa2dd7ae9b73d685f1009 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 17:25:54 +0200 Subject: [PATCH 27/45] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3ba713b..1b0235de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ will consitute of a breaking change warranting a new major release: - Small fix for `install-obsw-yocto.sh` script +## Added + +- Add a way for the MAX31865 RTD handlers to recognize faulty/broken/off sensor devices. + # [v1.44.1] 2023-04-12 - eive-tmtc: v2.22.1 From 41ec6dc0f2efac827da16d72eba6a7ffd5c483f7 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 18:06:04 +0200 Subject: [PATCH 28/45] set pref sd as param --- CHANGELOG.md | 3 +++ bsp_q7s/core/CoreController.cpp | 40 ++++++++++++++++++++++++++++++++- bsp_q7s/core/CoreController.h | 16 ++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b0235de..bcbc7a62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ will consitute of a breaking change warranting a new major release: ## Added - Add a way for the MAX31865 RTD handlers to recognize faulty/broken/off sensor devices. +- Add parameter interface for core controller +- Allow setting the preferred SD card via the new parameter interface of the core controller + with domain ID 0 and unque ID 0. # [v1.44.1] 2023-04-12 diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 554e5268..45a1326a 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -40,7 +40,8 @@ CoreController::CoreController(object_id_t objectId, bool enableHkSet) cmdRepliesSizes(128), opDivider5(5), opDivider10(10), - hkSet(this) { + hkSet(this), + paramHelper(this) { cmdExecutor.setRingBuffer(&cmdReplyBuf, &cmdRepliesSizes); try { sdcMan = SdCardManager::instance(); @@ -88,6 +89,10 @@ CoreController::CoreController(object_id_t objectId, bool enableHkSet) CoreController::~CoreController() {} ReturnValue_t CoreController::handleCommandMessage(CommandMessage *message) { + ReturnValue_t result = paramHelper.handleParameterMessage(message); + if(result == returnvalue::OK) { + return result; + } return ExtendedControllerBase::handleCommandMessage(message); } @@ -154,6 +159,11 @@ ReturnValue_t CoreController::initialize() { << std::endl; } + result = paramHelper.initialize(); + if(result != returnvalue::OK) { + return result; + } + sdStateMachine(); triggerEvent(core::REBOOT_SW, CURRENT_CHIP, CURRENT_COPY); @@ -2128,3 +2138,31 @@ bool CoreController::isNumber(const std::string &s) { return !s.empty() && std::find_if(s.begin(), s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end(); } + +ReturnValue_t CoreController::getParameter(uint8_t domainId, uint8_t uniqueIdentifier, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, + uint16_t startAtIndex) { + if(domainId != 0) { + return HasParametersIF::INVALID_DOMAIN_ID; + } + if(uniqueIdentifier >= ParamId::NUM_IDS) { + return HasParametersIF::INVALID_IDENTIFIER_ID; + } + uint8_t newPrefSd; + ReturnValue_t result = newValues->getElement(&newPrefSd); + if (result != returnvalue::OK) { + return result; + } + // Only SD card 0 (0) and 1 (1) are allowed values. + if(newPrefSd > 1) { + return HasParametersIF::INVALID_VALUE; + } + result = sdcMan->setPreferredSdCard(static_cast(newPrefSd)); + if(result != returnvalue::OK) { + return returnvalue::FAILED; + } + parameterWrapper->set(prefSdRaw); + return returnvalue::OK; + +} diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index 22b1f6ff..c5a5356a 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,8 +50,14 @@ struct RebootFile { xsc::Copy mechanismNextCopy = xsc::Copy::NO_COPY; }; -class CoreController : public ExtendedControllerBase { +class CoreController : public ExtendedControllerBase, + public ReceivesParameterMessagesIF { public: + enum ParamId: uint8_t { + PREF_SD = 0, + NUM_IDS + }; + static xsc::Chip CURRENT_CHIP; static xsc::Copy CURRENT_COPY; @@ -152,6 +160,7 @@ class CoreController : public ExtendedControllerBase { SdCardManager* sdcMan = nullptr; MessageQueueIF* eventQueue = nullptr; + uint8_t prefSdRaw = sd::SdCard::SLOT_0; SdStates sdFsmState = SdStates::START; SdStates fsmStateAfterDelay = SdStates::IDLE; enum SdCfgMode { PASSIVE, COLD_REDUNDANT, HOT_REDUNDANT }; @@ -216,10 +225,15 @@ class CoreController : public ExtendedControllerBase { core::HkSet hkSet; + ParameterHelper paramHelper; + #if OBSW_SD_CARD_MUST_BE_ON == 1 bool remountAttemptFlag = true; #endif + ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, + ParameterWrapper *parameterWrapper, + const ParameterWrapper *newValues, uint16_t startAtIndex) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; From 2262a15e35e912db143cb506d0b00102c47d348f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 18:11:20 +0200 Subject: [PATCH 29/45] compile fix --- bsp_q7s/core/CoreController.cpp | 4 ++++ bsp_q7s/core/CoreController.h | 1 + 2 files changed, 5 insertions(+) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 45a1326a..14f6c782 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -2134,6 +2134,10 @@ void CoreController::announceBootCounts() { totalBootCount & 0xffffffff); } +MessageQueueId_t CoreController::getCommandQueue() const { + return ExtendedControllerBase::getCommandQueue(); +} + bool CoreController::isNumber(const std::string &s) { return !s.empty() && std::find_if(s.begin(), s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end(); diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index c5a5356a..6e3da4bb 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -231,6 +231,7 @@ class CoreController : public ExtendedControllerBase, bool remountAttemptFlag = true; #endif + MessageQueueId_t getCommandQueue() const override; ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) override; From dd211cdf545cd43ace4933360b056d7d853bf67a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 12 Apr 2023 18:11:41 +0200 Subject: [PATCH 30/45] afmt --- bsp_q7s/core/CoreController.cpp | 39 ++++++++++++++++----------------- bsp_q7s/core/CoreController.h | 12 ++++------ 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 14f6c782..8486bd09 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -90,7 +90,7 @@ CoreController::~CoreController() {} ReturnValue_t CoreController::handleCommandMessage(CommandMessage *message) { ReturnValue_t result = paramHelper.handleParameterMessage(message); - if(result == returnvalue::OK) { + if (result == returnvalue::OK) { return result; } return ExtendedControllerBase::handleCommandMessage(message); @@ -160,7 +160,7 @@ ReturnValue_t CoreController::initialize() { } result = paramHelper.initialize(); - if(result != returnvalue::OK) { + if (result != returnvalue::OK) { return result; } @@ -2147,26 +2147,25 @@ ReturnValue_t CoreController::getParameter(uint8_t domainId, uint8_t uniqueIdent ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, uint16_t startAtIndex) { - if(domainId != 0) { + if (domainId != 0) { return HasParametersIF::INVALID_DOMAIN_ID; } - if(uniqueIdentifier >= ParamId::NUM_IDS) { + if (uniqueIdentifier >= ParamId::NUM_IDS) { return HasParametersIF::INVALID_IDENTIFIER_ID; } - uint8_t newPrefSd; - ReturnValue_t result = newValues->getElement(&newPrefSd); - if (result != returnvalue::OK) { - return result; - } - // Only SD card 0 (0) and 1 (1) are allowed values. - if(newPrefSd > 1) { - return HasParametersIF::INVALID_VALUE; - } - result = sdcMan->setPreferredSdCard(static_cast(newPrefSd)); - if(result != returnvalue::OK) { - return returnvalue::FAILED; - } - parameterWrapper->set(prefSdRaw); - return returnvalue::OK; - + uint8_t newPrefSd; + ReturnValue_t result = newValues->getElement(&newPrefSd); + if (result != returnvalue::OK) { + return result; + } + // Only SD card 0 (0) and 1 (1) are allowed values. + if (newPrefSd > 1) { + return HasParametersIF::INVALID_VALUE; + } + result = sdcMan->setPreferredSdCard(static_cast(newPrefSd)); + if (result != returnvalue::OK) { + return returnvalue::FAILED; + } + parameterWrapper->set(prefSdRaw); + return returnvalue::OK; } diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index 6e3da4bb..0f2d4033 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -50,13 +50,9 @@ struct RebootFile { xsc::Copy mechanismNextCopy = xsc::Copy::NO_COPY; }; -class CoreController : public ExtendedControllerBase, - public ReceivesParameterMessagesIF { +class CoreController : public ExtendedControllerBase, public ReceivesParameterMessagesIF { public: - enum ParamId: uint8_t { - PREF_SD = 0, - NUM_IDS - }; + enum ParamId : uint8_t { PREF_SD = 0, NUM_IDS }; static xsc::Chip CURRENT_CHIP; static xsc::Copy CURRENT_COPY; @@ -233,8 +229,8 @@ class CoreController : public ExtendedControllerBase, MessageQueueId_t getCommandQueue() const override; ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, - ParameterWrapper *parameterWrapper, - const ParameterWrapper *newValues, uint16_t startAtIndex) override; + ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, + uint16_t startAtIndex) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; From ea606ce21748810f5f4b52d23ce91a58ed081642 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 12:08:31 +0200 Subject: [PATCH 31/45] adaptions and possible small fix for update process --- linux/acs/StrComHandler.cpp | 76 ++++++++++++++++++++++--------------- tmtc | 2 +- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/linux/acs/StrComHandler.cpp b/linux/acs/StrComHandler.cpp index 303c2228..4b3500c3 100644 --- a/linux/acs/StrComHandler.cpp +++ b/linux/acs/StrComHandler.cpp @@ -89,7 +89,7 @@ ReturnValue_t StrComHandler::performOperation(uint8_t operationCode) { break; } case InternalState::FIRMWARE_UPDATE: { - replyTimeout.setTimeout(200); + replyTimeout.setTimeout(2000); resetReplyHandlingState(); result = performFirmwareUpdate(); if (result == returnvalue::OK) { @@ -390,7 +390,8 @@ ReturnValue_t StrComHandler::performFlashWrite() { #endif ReturnValue_t result = returnvalue::OK; uint32_t size = 0; - uint32_t bytesWritten = 0; + uint32_t bytesWrittenInRegion = 0; + size_t totalBytesWritten = 0; uint32_t fileSize = 0; struct WriteActionRequest req; @@ -412,20 +413,18 @@ ReturnValue_t StrComHandler::performFlashWrite() { ProgressPrinter progressPrinter("Flash write", fileSize); #endif /* OBSW_DEBUG_STARTRACKER == 1 */ uint32_t fileChunks = fileSize / CHUNK_SIZE; - bytesWritten = 0; + bytesWrittenInRegion = 0; req.region = flashWrite.firstRegion; req.length = CHUNK_SIZE; - for (uint32_t idx = 0; idx < fileChunks; idx++) { - if (terminate) { - return returnvalue::OK; - } - file.seekg(idx * CHUNK_SIZE, file.beg); + + auto writeNextSegment = [&](uint32_t chunkIdx) { + file.seekg(chunkIdx * CHUNK_SIZE, file.beg); file.read(reinterpret_cast(req.data), CHUNK_SIZE); - if (bytesWritten + CHUNK_SIZE > FLASH_REGION_SIZE) { + if (bytesWrittenInRegion + CHUNK_SIZE > FLASH_REGION_SIZE) { req.region++; - bytesWritten = 0; + bytesWrittenInRegion = 0; } - req.address = bytesWritten; + req.address = bytesWrittenInRegion; arc_pack_write_action_req(&req, cmdBuf.data(), &size); result = sendAndRead(size, req.address); if (result != returnvalue::OK) { @@ -435,34 +434,49 @@ ReturnValue_t StrComHandler::performFlashWrite() { if (result != returnvalue::OK) { return result; } - bytesWritten += CHUNK_SIZE; + totalBytesWritten += CHUNK_SIZE; + bytesWrittenInRegion += CHUNK_SIZE; #if OBSW_DEBUG_STARTRACKER == 1 - progressPrinter.print(idx * CHUNK_SIZE); + progressPrinter.print(chunkIdx * CHUNK_SIZE); #endif /* OBSW_DEBUG_STARTRACKER == 1 */ + return result; + }; + + for (uint32_t idx = 0; idx < fileChunks; idx++) { + if (terminate) { + return returnvalue::OK; + } + result = writeNextSegment(idx); + if(result != returnvalue::OK) { + return result; + } if (idx % 50 == 0) { // Some grace time for other tasks TaskFactory::delayTask(2); } } uint32_t remainingBytes = fileSize - fileChunks * CHUNK_SIZE; - file.seekg((fileChunks - 1) * CHUNK_SIZE, file.beg); - file.read(reinterpret_cast(req.data), remainingBytes); - file.close(); - if (bytesWritten + CHUNK_SIZE > FLASH_REGION_SIZE) { - req.region++; - bytesWritten = 0; - } - req.address = bytesWritten; - req.length = remainingBytes; - bytesWritten += remainingBytes; - arc_pack_write_action_req(&req, cmdBuf.data(), &size); - result = sendAndRead(size, req.address); - if (result != returnvalue::OK) { - return result; - } - result = checkActionReply(replyLen); - if (result != returnvalue::OK) { - return result; + if (remainingBytes > 0) { + file.seekg(fileChunks * CHUNK_SIZE, file.beg); + file.read(reinterpret_cast(req.data), remainingBytes); + file.close(); + if (bytesWrittenInRegion + CHUNK_SIZE > FLASH_REGION_SIZE) { + req.region++; + bytesWrittenInRegion = 0; + } + req.address = bytesWrittenInRegion; + req.length = remainingBytes; + totalBytesWritten += CHUNK_SIZE; + bytesWrittenInRegion += remainingBytes; + arc_pack_write_action_req(&req, cmdBuf.data(), &size); + result = sendAndRead(size, req.address); + if (result != returnvalue::OK) { + return result; + } + result = checkActionReply(replyLen); + if (result != returnvalue::OK) { + return result; + } } #if OBSW_DEBUG_STARTRACKER == 1 progressPrinter.print(fileSize); diff --git a/tmtc b/tmtc index 01b3a894..33fd280e 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 01b3a894e66e7f38dd2e7a35e329e99a6199b7f1 +Subproject commit 33fd280e517a55175072ea336c7f8e85bce6e55a From 8620bd02834ffba427a044fa6076429ab9472f82 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 12:35:56 +0200 Subject: [PATCH 32/45] avoid faulty reply for STR special requests --- linux/acs/StrComHandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux/acs/StrComHandler.cpp b/linux/acs/StrComHandler.cpp index 4b3500c3..3c88a71b 100644 --- a/linux/acs/StrComHandler.cpp +++ b/linux/acs/StrComHandler.cpp @@ -125,6 +125,7 @@ ReturnValue_t StrComHandler::startImageUpload(std::string fullname) { } { MutexGuard mg(lock); + replyWasReceived = false; state = InternalState::UPLOAD_IMAGE; } semaphore.release(); @@ -151,6 +152,7 @@ ReturnValue_t StrComHandler::startImageDownload(std::string path) { downloadImage.path = path; { MutexGuard mg(lock); + replyWasReceived = false; state = InternalState::DOWNLOAD_IMAGE; } terminate = false; @@ -187,6 +189,7 @@ ReturnValue_t StrComHandler::startFirmwareUpdate(std::string fullname) { flashWrite.lastRegion = static_cast(startracker::FirmwareRegions::LAST); { MutexGuard mg(lock); + replyWasReceived = false; state = InternalState::FIRMWARE_UPDATE; } semaphore.release(); @@ -216,6 +219,7 @@ ReturnValue_t StrComHandler::startFlashRead(std::string path, uint8_t startRegio flashRead.size = length; { MutexGuard mg(lock); + replyWasReceived = false; state = InternalState::FLASH_READ; } semaphore.release(); From f7bc052070e73f25ace3b69cacf70ac38f6b88a1 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 17:55:56 +0200 Subject: [PATCH 33/45] stupid submodules --- .gitmodules | 3 --- CMakeLists.txt | 2 +- linux/acs/StrComHandler.h | 6 ++++-- mission/acs/str/ArcsecDatalinkLayer.cpp | 13 +++++++------ mission/acs/str/ArcsecDatalinkLayer.h | 5 ++++- mission/acs/str/ArcsecJsonParamBase.cpp | 6 +++++- mission/acs/str/ArcsecJsonParamBase.h | 2 -- mission/acs/str/StarTrackerHandler.cpp | 9 +++++---- mission/acs/str/StarTrackerHandler.h | 2 +- thirdparty/CMakeLists.txt | 3 ++- thirdparty/arcsec_star_tracker | 1 - 11 files changed, 29 insertions(+), 23 deletions(-) delete mode 160000 thirdparty/arcsec_star_tracker diff --git a/.gitmodules b/.gitmodules index 76fb8527..2bcea610 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "thirdparty/lwgps"] path = thirdparty/lwgps url = https://github.com/rmspacefish/lwgps.git -[submodule "thirdparty/arcsec_star_tracker"] - path = thirdparty/arcsec_star_tracker - url = https://egit.irs.uni-stuttgart.de/eive/arcsec_star_tracker.git [submodule "thirdparty/json"] path = thirdparty/json url = https://github.com/nlohmann/json.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d73475d..76db1b78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,7 +220,7 @@ set(LIB_EIVE_MISSION_PATH mission) set(LIB_ETL_PATH ${THIRD_PARTY_FOLDER}/etl) set(LIB_CATCH2_PATH ${THIRD_PARTY_FOLDER}/Catch2) set(LIB_LWGPS_PATH ${THIRD_PARTY_FOLDER}/lwgps) -set(LIB_ARCSEC_PATH ${THIRD_PARTY_FOLDER}/arcsec_star_tracker) +set(LIB_ARCSEC_PATH ${THIRD_PARTY_FOLDER}/sagittactl) set(LIB_JSON_PATH ${THIRD_PARTY_FOLDER}/json) set(FSFW_WARNING_SHADOW_LOCAL_GCC OFF) diff --git a/linux/acs/StrComHandler.h b/linux/acs/StrComHandler.h index 385e8b2e..d8542f26 100644 --- a/linux/acs/StrComHandler.h +++ b/linux/acs/StrComHandler.h @@ -11,8 +11,6 @@ #include "bsp_q7s/fs/SdCardManager.h" #endif -#include "arcsec/client/generated/actionreq.h" -#include "arcsec/common/generated/tmtcstructs.h" #include "fsfw/devicehandlers/CookieIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/osal/linux/BinarySemaphore.h" @@ -20,6 +18,10 @@ #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw_hal/linux/serial/SerialComIF.h" +extern "C" { +#include +} + /** * @brief Helper class for the star tracker handler to accelerate large data transfers. * diff --git a/mission/acs/str/ArcsecDatalinkLayer.cpp b/mission/acs/str/ArcsecDatalinkLayer.cpp index 532c12b8..e192be2e 100644 --- a/mission/acs/str/ArcsecDatalinkLayer.cpp +++ b/mission/acs/str/ArcsecDatalinkLayer.cpp @@ -1,4 +1,8 @@ -#include +#include "ArcsecDatalinkLayer.h" + +extern "C" { +#include +} ArcsecDatalinkLayer::ArcsecDatalinkLayer() : decodeRingBuf(BUFFER_LENGTHS, true) { slipInit(); } @@ -18,13 +22,10 @@ ReturnValue_t ArcsecDatalinkLayer::checkRingBufForFrame(const uint8_t** decodedF case ARC_DEC_INPROGRESS: { break; } - case ARC_DEC_ERROR_FRAME_SHORT: { + case ARC_DEC_ERROR: { decodeRingBuf.deleteData(idx); - return REPLY_TOO_SHORT; + return returnvalue::FAILED; } - case ARC_DEC_ERROR_CHECKSUM: - decodeRingBuf.deleteData(idx); - return CRC_FAILURE; case ARC_DEC_ASYNC: case ARC_DEC_SYNC: { // Reset length of SLIP struct for next frame diff --git a/mission/acs/str/ArcsecDatalinkLayer.h b/mission/acs/str/ArcsecDatalinkLayer.h index 404d9e52..b1a7fd94 100644 --- a/mission/acs/str/ArcsecDatalinkLayer.h +++ b/mission/acs/str/ArcsecDatalinkLayer.h @@ -5,10 +5,13 @@ #include #include -#include "arcsec/common/misc.h" #include "eive/resultClassIds.h" #include "fsfw/returnvalues/returnvalue.h" +extern "C" { +#include +} + /** * @brief Helper class to handle the datalinklayer of replies from the star tracker of arcsec. */ diff --git a/mission/acs/str/ArcsecJsonParamBase.cpp b/mission/acs/str/ArcsecJsonParamBase.cpp index b5dd2150..6bdaa505 100644 --- a/mission/acs/str/ArcsecJsonParamBase.cpp +++ b/mission/acs/str/ArcsecJsonParamBase.cpp @@ -1,7 +1,11 @@ +#include "arcsecJsonKeys.h" + #include #include -#include "arcsecJsonKeys.h" +extern "C" { +#include +} ArcsecJsonParamBase::ArcsecJsonParamBase(std::string setName) : setName(setName) {} diff --git a/mission/acs/str/ArcsecJsonParamBase.h b/mission/acs/str/ArcsecJsonParamBase.h index 90c54f45..4c4a7a90 100644 --- a/mission/acs/str/ArcsecJsonParamBase.h +++ b/mission/acs/str/ArcsecJsonParamBase.h @@ -7,8 +7,6 @@ #include #include -#include "arcsec/common/generated/tmtcstructs.h" -#include "arcsec/common/genericstructs.h" #include "eive/resultClassIds.h" #include "fsfw/returnvalues/returnvalue.h" diff --git a/mission/acs/str/StarTrackerHandler.cpp b/mission/acs/str/StarTrackerHandler.cpp index 3837d9e5..b449c036 100644 --- a/mission/acs/str/StarTrackerHandler.cpp +++ b/mission/acs/str/StarTrackerHandler.cpp @@ -1,18 +1,19 @@ -#include -#include -#include #include #include #include #include #include +#include +#include +#include + #include #include #include #include "OBSWConfig.h" -#include "arcsec/common/misc.h" +//#include "/common/misc.h" std::atomic_bool JCFG_DONE(false); diff --git a/mission/acs/str/StarTrackerHandler.h b/mission/acs/str/StarTrackerHandler.h index f143a660..4b8ba449 100644 --- a/mission/acs/str/StarTrackerHandler.h +++ b/mission/acs/str/StarTrackerHandler.h @@ -10,7 +10,7 @@ #include #include "OBSWConfig.h" -#include "arcsec/common/SLIP.h" +#include "common/SLIP.h" #include "devices/powerSwitcherList.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/src/fsfw/serialize/SerializeAdapter.h" diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index e300cd11..3a5110c9 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -4,7 +4,8 @@ endif() # Dependency on proprietary library if(TGT_BSP MATCHES "arm/q7s") - add_subdirectory(arcsec_star_tracker) + # Only add required folder for wire library. + add_subdirectory(sagittactl/wire) endif() add_subdirectory(rapidcsv) diff --git a/thirdparty/arcsec_star_tracker b/thirdparty/arcsec_star_tracker deleted file mode 160000 index 2823952e..00000000 --- a/thirdparty/arcsec_star_tracker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2823952e0902726e6e35dd7c159761f76bf7e505 From 3ff8c6a481bc82116300f3a9dc334bd1139e0f2d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 17:58:36 +0200 Subject: [PATCH 34/45] re-add str submodule --- .gitmodules | 3 +++ thirdparty/sagittactl | 1 + 2 files changed, 4 insertions(+) create mode 160000 thirdparty/sagittactl diff --git a/.gitmodules b/.gitmodules index 2bcea610..e1ea03a4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "thirdparty/gomspace-sw"] path = thirdparty/gomspace-sw url = https://egit.irs.uni-stuttgart.de/eive/gomspace-sw.git +[submodule "thirdparty/sagittactl"] + path = thirdparty/sagittactl + url = https://egit.irs.uni-stuttgart.de/eive/sagittactl.git diff --git a/thirdparty/sagittactl b/thirdparty/sagittactl new file mode 160000 index 00000000..3ab9b2cf --- /dev/null +++ b/thirdparty/sagittactl @@ -0,0 +1 @@ +Subproject commit 3ab9b2cf56dea1cf19c7d46eb88a967939968acd From 29dc684455fc107feb9acce763931849b6c0dbcc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 18:09:02 +0200 Subject: [PATCH 35/45] update done, compiles again --- mission/acs/str/ArcsecDatalinkLayer.cpp | 2 +- mission/acs/str/ArcsecDatalinkLayer.h | 2 +- mission/acs/str/ArcsecJsonParamBase.cpp | 2 +- mission/acs/str/StarTrackerHandler.cpp | 7 +++---- mission/acs/str/StarTrackerHandler.h | 5 ++++- thirdparty/sagittactl | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mission/acs/str/ArcsecDatalinkLayer.cpp b/mission/acs/str/ArcsecDatalinkLayer.cpp index e192be2e..d67f6e75 100644 --- a/mission/acs/str/ArcsecDatalinkLayer.cpp +++ b/mission/acs/str/ArcsecDatalinkLayer.cpp @@ -1,7 +1,7 @@ #include "ArcsecDatalinkLayer.h" extern "C" { -#include +#include } ArcsecDatalinkLayer::ArcsecDatalinkLayer() : decodeRingBuf(BUFFER_LENGTHS, true) { slipInit(); } diff --git a/mission/acs/str/ArcsecDatalinkLayer.h b/mission/acs/str/ArcsecDatalinkLayer.h index b1a7fd94..1453e517 100644 --- a/mission/acs/str/ArcsecDatalinkLayer.h +++ b/mission/acs/str/ArcsecDatalinkLayer.h @@ -9,7 +9,7 @@ #include "fsfw/returnvalues/returnvalue.h" extern "C" { -#include +#include } /** diff --git a/mission/acs/str/ArcsecJsonParamBase.cpp b/mission/acs/str/ArcsecJsonParamBase.cpp index 6bdaa505..ff1f59d2 100644 --- a/mission/acs/str/ArcsecJsonParamBase.cpp +++ b/mission/acs/str/ArcsecJsonParamBase.cpp @@ -4,7 +4,7 @@ #include extern "C" { -#include +#include } ArcsecJsonParamBase::ArcsecJsonParamBase(std::string setName) : setName(setName) {} diff --git a/mission/acs/str/StarTrackerHandler.cpp b/mission/acs/str/StarTrackerHandler.cpp index b449c036..54af25da 100644 --- a/mission/acs/str/StarTrackerHandler.cpp +++ b/mission/acs/str/StarTrackerHandler.cpp @@ -4,16 +4,15 @@ #include #include -#include -#include -#include +extern "C" { +#include +} #include #include #include #include "OBSWConfig.h" -//#include "/common/misc.h" std::atomic_bool JCFG_DONE(false); diff --git a/mission/acs/str/StarTrackerHandler.h b/mission/acs/str/StarTrackerHandler.h index 4b8ba449..ea46cb43 100644 --- a/mission/acs/str/StarTrackerHandler.h +++ b/mission/acs/str/StarTrackerHandler.h @@ -10,12 +10,15 @@ #include #include "OBSWConfig.h" -#include "common/SLIP.h" #include "devices/powerSwitcherList.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/src/fsfw/serialize/SerializeAdapter.h" #include "fsfw/timemanager/Countdown.h" +extern "C" { +#include +} + /** * @brief This is the device handler for the star tracker from arcsec. * diff --git a/thirdparty/sagittactl b/thirdparty/sagittactl index 3ab9b2cf..64332216 160000 --- a/thirdparty/sagittactl +++ b/thirdparty/sagittactl @@ -1 +1 @@ -Subproject commit 3ab9b2cf56dea1cf19c7d46eb88a967939968acd +Subproject commit 64332216c193fa6483258060b53fc2842c08dcf4 From 906aedc911eee1e2f4fbd0c7576ee8260600ae7c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 18:13:12 +0200 Subject: [PATCH 36/45] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcbc7a62..84ed0cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ will consitute of a breaking change warranting a new major release: ## Fixed - Small fix for `install-obsw-yocto.sh` script +- Bugfix for STR firmware update procedure where the last remaining + bytes were not written properly. ## Added From 2722e471ef08a35196f6d8267e65b1e1b0950c39 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 18:14:30 +0200 Subject: [PATCH 37/45] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12abd808..83224fae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ will consitute of a breaking change warranting a new major release: # [unreleased] - q7s-package: v2.5.0 +- STR firmware was updated to v10.3 ## Fixed @@ -24,6 +25,10 @@ will consitute of a breaking change warranting a new major release: - Bugfix for STR firmware update procedure where the last remaining bytes were not written properly. +## Changed + +- STR `wire` library updated to v10.3. Submodule renamed to `sagittactl`. + ## Added - Add a way for the MAX31865 RTD handlers to recognize faulty/broken/off sensor devices. @@ -31,6 +36,7 @@ will consitute of a breaking change warranting a new major release: - Allow setting the preferred SD card via the new parameter interface of the core controller with domain ID 0 and unque ID 0. + # [v1.44.1] 2023-04-12 - eive-tmtc: v2.22.1 From 600d0c580d381c394ed4a0ff76a50facdee80aab Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 18:20:23 +0200 Subject: [PATCH 38/45] another changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12abd808..1166f514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ will consitute of a breaking change warranting a new major release: - Small fix for `install-obsw-yocto.sh` script - Bugfix for STR firmware update procedure where the last remaining bytes were not written properly. +- Bugfix for STR where an invalid reply was received for special requests + like firmware updates. ## Added From 3e3ac9f5befeafa3b24dcd2f849b364aa40fd2e2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 21:14:38 +0200 Subject: [PATCH 39/45] conditional build of STR components --- linux/acs/CMakeLists.txt | 10 +++++++--- linux/acs/StrComHandler.cpp | 2 +- mission/acs/str/ArcsecJsonParamBase.cpp | 4 ++-- unittest/controller/testThermalController.cpp | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/linux/acs/CMakeLists.txt b/linux/acs/CMakeLists.txt index 99cacbc2..5b5b5ac8 100644 --- a/linux/acs/CMakeLists.txt +++ b/linux/acs/CMakeLists.txt @@ -1,6 +1,10 @@ -target_sources( - ${OBSW_NAME} PUBLIC AcsBoardPolling.cpp ImtqPollingTask.cpp RwPollingTask.cpp - SusPolling.cpp StrComHandler.cpp) +target_sources(${OBSW_NAME} PUBLIC AcsBoardPolling.cpp ImtqPollingTask.cpp + RwPollingTask.cpp SusPolling.cpp) + +# Dependency on proprietary library +if(TGT_BSP MATCHES "arm/q7s") + target_sources(${OBSW_NAME} PUBLIC StrComHandler.cpp) +endif() if(EIVE_BUILD_GPSD_GPS_HANDLER) target_sources(${OBSW_NAME} PRIVATE GpsHyperionLinuxController.cpp) diff --git a/linux/acs/StrComHandler.cpp b/linux/acs/StrComHandler.cpp index 3c88a71b..51c66f18 100644 --- a/linux/acs/StrComHandler.cpp +++ b/linux/acs/StrComHandler.cpp @@ -451,7 +451,7 @@ ReturnValue_t StrComHandler::performFlashWrite() { return returnvalue::OK; } result = writeNextSegment(idx); - if(result != returnvalue::OK) { + if (result != returnvalue::OK) { return result; } if (idx % 50 == 0) { diff --git a/mission/acs/str/ArcsecJsonParamBase.cpp b/mission/acs/str/ArcsecJsonParamBase.cpp index ff1f59d2..58c54d30 100644 --- a/mission/acs/str/ArcsecJsonParamBase.cpp +++ b/mission/acs/str/ArcsecJsonParamBase.cpp @@ -1,8 +1,8 @@ -#include "arcsecJsonKeys.h" - #include #include +#include "arcsecJsonKeys.h" + extern "C" { #include } diff --git a/unittest/controller/testThermalController.cpp b/unittest/controller/testThermalController.cpp index 0e12d94d..c2166ca0 100644 --- a/unittest/controller/testThermalController.cpp +++ b/unittest/controller/testThermalController.cpp @@ -47,8 +47,8 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { CommandMessage modeMessage; - ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, - HasModesIF::MODE_ON, HasModesIF::SUBMODE_NONE); + ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_ON, + HasModesIF::SUBMODE_NONE); MessageQueueIF* commandQueue = QueueFactory::instance()->createMessageQueue(5, MessageQueueMessage::MAX_MESSAGE_SIZE); From aa746276aeb7278d6028c70b316f2ba7c6bbca41 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 21:15:10 +0200 Subject: [PATCH 40/45] disable TCS test --- mission/controller/ThermalController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index b12088ae..82efb85c 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -17,7 +17,7 @@ #include // Enabling this should trigger a special event which in turn should trigger a system reaction. -#define LOWER_SYRLINKS_UPPER_LIMITS 1 +#define LOWER_SYRLINKS_UPPER_LIMITS 0 #define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_PLOC_UPPER_LIMITS 0 From af354bd9fb3551d6c853e5116a264051c15ae89f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 23:24:32 +0200 Subject: [PATCH 41/45] systemctl helper --- bsp_q7s/core/CoreController.cpp | 37 +++++++++++++++++-- bsp_q7s/core/CoreController.h | 20 ++-------- linux/acs/StrComHandler.cpp | 2 +- mission/sysDefs.h | 21 ++++++++++- unittest/controller/testThermalController.cpp | 4 +- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 8486bd09..8961a578 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -9,7 +9,6 @@ #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/timemanager/Stopwatch.h" #include "fsfw/version.h" -#include "mission/sysDefs.h" #include "watchdog/definitions.h" #if OBSW_ADD_TMTC_UDP_SERVER == 1 #include "fsfw/osal/common/UdpTmTcBridge.h" @@ -118,7 +117,7 @@ void CoreController::performControlOperation() { bool replyReceived = false; // TODO: We could read the data in the ring buffer and send it as an action data reply. if (cmdExecutor.check(replyReceived) == CommandExecutor::EXECUTION_FINISHED) { - actionHelper.finish(true, successRecipient, core::EXECUTE_SHELL_CMD); + actionHelper.finish(true, successRecipient, core::EXECUTE_SHELL_CMD_BLOCKING); shellCmdIsExecuting = false; cmdReplyBuf.clear(); while (not cmdRepliesSizes.empty()) { @@ -304,6 +303,38 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ // Completion will be reported by SD card state machine return returnvalue::OK; } + case (SYSTEMCTL_CMD_EXECUTOR): { + // Expect one byte systemctl command type and a unit name with at least one byte as minimum. + if (size < 2) { + return HasActionsIF::INVALID_PARAMETERS; + } + if (data[0] >= core::SystemctlCmd::NUM_CMDS) { + return HasActionsIF::INVALID_PARAMETERS; + } + core::SystemctlCmd cmdType = static_cast(data[0]); + std::string unitName = std::string(reinterpret_cast(data + 1), size - 1); + std::ostringstream oss("systemctl "); + switch (cmdType) { + case (core::SystemctlCmd::START): { + oss << "start "; + break; + } + case (core::SystemctlCmd::STOP): { + oss << "stop "; + break; + } + case (core::SystemctlCmd::RESTART): { + oss << "restart "; + break; + } + } + oss << unitName; + int result = std::system(oss.str().c_str()); + if (result != 0) { + return returnvalue::FAILED; + } + return EXECUTION_FINISHED; + } case (SWITCH_IMG_LOCK): { if (size != 3) { return HasActionsIF::INVALID_PARAMETERS; @@ -334,7 +365,7 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ // Warning: This function will never return, because it reboots the system return actionReboot(data, size); } - case (EXECUTE_SHELL_CMD): { + case (EXECUTE_SHELL_CMD_BLOCKING): { std::string cmd = std::string(cmd, size); if (cmdExecutor.getCurrentState() == CommandExecutor::States::PENDING or shellCmdIsExecuting) { diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index 0f2d4033..c1f5e40d 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -18,17 +18,11 @@ #include "bsp_q7s/fs/SdCardManager.h" #include "events/subsystemIdRanges.h" #include "fsfw/controller/ExtendedControllerBase.h" +#include "mission/sysDefs.h" class Timer; class SdCardManager; -namespace xsc { - -enum Chip : int { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP }; -enum Copy : int { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY }; - -} // namespace xsc - struct RebootFile { static constexpr uint8_t DEFAULT_MAX_BOOT_CNT = 10; @@ -61,18 +55,12 @@ class CoreController : public ExtendedControllerBase, public ReceivesParameterMe static constexpr char CHIP_STATE_FILE[] = "/tmp/chip_prot_status.txt"; static constexpr char CURR_COPY_FILE[] = "/tmp/curr_copy.txt"; - static constexpr char CONF_FOLDER[] = "conf"; - - static constexpr char VERSION_FILE_NAME[] = "version.txt"; - static constexpr char REBOOT_FILE_NAME[] = "reboot.txt"; - static constexpr char TIME_FILE_NAME[] = "time_backup.txt"; - const std::string VERSION_FILE = - "/" + std::string(CONF_FOLDER) + "/" + std::string(VERSION_FILE_NAME); + "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::VERSION_FILE_NAME); const std::string REBOOT_FILE = - "/" + std::string(CONF_FOLDER) + "/" + std::string(REBOOT_FILE_NAME); + "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::REBOOT_FILE_NAME); const std::string BACKUP_TIME_FILE = - "/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_FILE_NAME); + "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::TIME_FILE_NAME); static constexpr char CHIP_0_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-nom-rootfs"; static constexpr char CHIP_0_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-gold-rootfs"; diff --git a/linux/acs/StrComHandler.cpp b/linux/acs/StrComHandler.cpp index 3c88a71b..51c66f18 100644 --- a/linux/acs/StrComHandler.cpp +++ b/linux/acs/StrComHandler.cpp @@ -451,7 +451,7 @@ ReturnValue_t StrComHandler::performFlashWrite() { return returnvalue::OK; } result = writeNextSegment(idx); - if(result != returnvalue::OK) { + if (result != returnvalue::OK) { return result; } if (idx % 50 == 0) { diff --git a/mission/sysDefs.h b/mission/sysDefs.h index 7a729d6e..b73e8f02 100644 --- a/mission/sysDefs.h +++ b/mission/sysDefs.h @@ -13,7 +13,25 @@ enum Mode : Mode_t { BOOT = 5, SAFE = acs::AcsMode::SAFE, PTG_IDLE = acs::AcsMod } +namespace xsc { + +enum Chip : int { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP }; +enum Copy : int { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY }; + +} // namespace xsc + namespace core { + +// TODO: Support for status? Or maybe some command to quickly get information whether a unit +// is running. +enum SystemctlCmd : uint8_t { START = 0, STOP = 1, RESTART = 2, NUM_CMDS = 3 }; + +static constexpr char CONF_FOLDER[] = "conf"; + +static constexpr char VERSION_FILE_NAME[] = "version.txt"; +static constexpr char REBOOT_FILE_NAME[] = "reboot.txt"; +static constexpr char TIME_FILE_NAME[] = "time_backup.txt"; + static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0; static constexpr ActionId_t ANNOUNCE_VERSION = 1; static constexpr ActionId_t ANNOUNCE_CURRENT_IMAGE = 2; @@ -37,7 +55,8 @@ static constexpr ActionId_t MOUNT_OTHER_COPY = 33; //! Reboot using the reboot command static constexpr ActionId_t REBOOT_OBC = 34; -static constexpr ActionId_t EXECUTE_SHELL_CMD = 40; +static constexpr ActionId_t EXECUTE_SHELL_CMD_BLOCKING = 40; +static constexpr ActionId_t SYSTEMCTL_CMD_EXECUTOR = 42; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; diff --git a/unittest/controller/testThermalController.cpp b/unittest/controller/testThermalController.cpp index 0e12d94d..c2166ca0 100644 --- a/unittest/controller/testThermalController.cpp +++ b/unittest/controller/testThermalController.cpp @@ -47,8 +47,8 @@ TEST_CASE("Thermal Controller", "[ThermalController]") { CommandMessage modeMessage; - ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, - HasModesIF::MODE_ON, HasModesIF::SUBMODE_NONE); + ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_ON, + HasModesIF::SUBMODE_NONE); MessageQueueIF* commandQueue = QueueFactory::instance()->createMessageQueue(5, MessageQueueMessage::MAX_MESSAGE_SIZE); From c5b26eade48bcef9de622da632b8093a48d5270b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 13 Apr 2023 23:34:11 +0200 Subject: [PATCH 42/45] now it compiles --- bsp_q7s/core/CoreController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 8961a578..05bf859b 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -1339,7 +1339,7 @@ void CoreController::performMountedSdCardOperations() { auto mountedSdCardOp = [&](sd::SdCard sdCard, std::string mntPoint) { if (not performOneShotSdCardOpsSwitch) { std::ostringstream path; - path << mntPoint << "/" << CONF_FOLDER; + path << mntPoint << "/" << core::CONF_FOLDER; std::error_code e; if (not std::filesystem::exists(path.str()), e) { bool created = std::filesystem::create_directory(path.str(), e); From f645b97ba3e65abde011da50facaaaf5d0bd7dac Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 14 Apr 2023 00:08:38 +0200 Subject: [PATCH 43/45] bump tmtc --- tmtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmtc b/tmtc index 33fd280e..8993ccdf 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 33fd280e517a55175072ea336c7f8e85bce6e55a +Subproject commit 8993ccdf66c54765fc2a10c26b9c340b7e6b9ffd From e17b8d2ec4e3990cbcc4ba60aa72ec3bf0a4d8a2 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 14 Apr 2023 00:21:28 +0200 Subject: [PATCH 44/45] add non-blocking shell cmd executor --- bsp_q7s/core/CoreController.cpp | 13 ++++++++++++- mission/sysDefs.h | 1 + tmtc | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 05bf859b..1931e19a 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -313,7 +313,7 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ } core::SystemctlCmd cmdType = static_cast(data[0]); std::string unitName = std::string(reinterpret_cast(data + 1), size - 1); - std::ostringstream oss("systemctl "); + std::ostringstream oss("systemctl ", std::ostringstream::ate); switch (cmdType) { case (core::SystemctlCmd::START): { oss << "start "; @@ -327,6 +327,9 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ oss << "restart "; break; } + default: { + return HasActionsIF::INVALID_PARAMETERS; + } } oss << unitName; int result = std::system(oss.str().c_str()); @@ -366,6 +369,14 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ return actionReboot(data, size); } case (EXECUTE_SHELL_CMD_BLOCKING): { + std::string cmd = std::string(cmd, size); + int result = std::system(cmd.c_str()); + if (result != 0) { + return returnvalue::FAILED; + } + return EXECUTION_FINISHED; + } + case (EXECUTE_SHELL_CMD_NON_BLOCKING): { std::string cmd = std::string(cmd, size); if (cmdExecutor.getCurrentState() == CommandExecutor::States::PENDING or shellCmdIsExecuting) { diff --git a/mission/sysDefs.h b/mission/sysDefs.h index b73e8f02..e8ada9f8 100644 --- a/mission/sysDefs.h +++ b/mission/sysDefs.h @@ -56,6 +56,7 @@ static constexpr ActionId_t MOUNT_OTHER_COPY = 33; static constexpr ActionId_t REBOOT_OBC = 34; static constexpr ActionId_t EXECUTE_SHELL_CMD_BLOCKING = 40; +static constexpr ActionId_t EXECUTE_SHELL_CMD_NON_BLOCKING = 41; static constexpr ActionId_t SYSTEMCTL_CMD_EXECUTOR = 42; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; diff --git a/tmtc b/tmtc index 8993ccdf..005e15b2 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 8993ccdf66c54765fc2a10c26b9c340b7e6b9ffd +Subproject commit 005e15b21bdb58109b90ffbe4be9fc76e85ca38f From bc6531f7a5df222f17d66c2677b80fdaf0b56c04 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 14 Apr 2023 00:29:21 +0200 Subject: [PATCH 45/45] bugfix for shell cmd executors --- CHANGELOG.md | 1 + bsp_q7s/core/CoreController.cpp | 9 +++++---- tmtc | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1166f514..731c87d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ will consitute of a breaking change warranting a new major release: bytes were not written properly. - Bugfix for STR where an invalid reply was received for special requests like firmware updates. +- Bugfix for shell command executors in command controller which lead to a crash. ## Added diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 1931e19a..e1033943 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -369,20 +369,21 @@ ReturnValue_t CoreController::executeAction(ActionId_t actionId, MessageQueueId_ return actionReboot(data, size); } case (EXECUTE_SHELL_CMD_BLOCKING): { - std::string cmd = std::string(cmd, size); - int result = std::system(cmd.c_str()); + std::string cmdToExecute = std::string(reinterpret_cast(data), size); + int result = std::system(cmdToExecute.c_str()); if (result != 0) { + // TODO: Data reply with returnalue maybe? return returnvalue::FAILED; } return EXECUTION_FINISHED; } case (EXECUTE_SHELL_CMD_NON_BLOCKING): { - std::string cmd = std::string(cmd, size); + std::string cmdToExecute = std::string(reinterpret_cast(data), size); if (cmdExecutor.getCurrentState() == CommandExecutor::States::PENDING or shellCmdIsExecuting) { return HasActionsIF::IS_BUSY; } - cmdExecutor.load(cmd, false, false); + cmdExecutor.load(cmdToExecute, false, false); ReturnValue_t result = cmdExecutor.execute(); if (result != returnvalue::OK) { return result; diff --git a/tmtc b/tmtc index 005e15b2..f8da9cff 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 005e15b21bdb58109b90ffbe4be9fc76e85ca38f +Subproject commit f8da9cff7c5d6d6bdd483f90ccefb67b2d1e11a4