From 397e23f1daae78eb98bcc903ae55f925c1fdc462 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:13:24 +0200 Subject: [PATCH 01/10] 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_ */ -- 2.43.0 From 44325ee1762e24ce389aabf83e8dcccbbdf8fbff Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:15:12 +0200 Subject: [PATCH 02/10] 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 -- 2.43.0 From 19006e79b12668d2655ccd2c09b2ee518a74fc11 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 12:53:35 +0200 Subject: [PATCH 03/10] 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(); -- 2.43.0 From 3a236a1a3bb095b1f55271f4d03c7f4901575460 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:01:31 +0200 Subject: [PATCH 04/10] 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); -- 2.43.0 From 64b4db98ba29f38eb9f526cda73357eb9dfd5d3e Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:02:53 +0200 Subject: [PATCH 05/10] 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. -- 2.43.0 From c5e18957f5a4b9f9c428e4fe7c8c0bfa30d92f46 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:03:28 +0200 Subject: [PATCH 06/10] 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 -- 2.43.0 From 7a53ada4b4ea3040b6470ea3defeb7f0cd1f9dfa Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:09:48 +0200 Subject: [PATCH 07/10] 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) { -- 2.43.0 From 086dbcc19e8ad572e951f1d41b0e6964861b9d6b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:16:50 +0200 Subject: [PATCH 08/10] 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; -- 2.43.0 From d7dc3f34c7aacd32a6e066d74f12336f8bce804b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 13:24:16 +0200 Subject: [PATCH 09/10] 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)); -- 2.43.0 From 4acf66a020eecb99c51a406e3f09d7bb461ff62d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 6 Apr 2023 15:31:32 +0200 Subject: [PATCH 10/10] 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); -- 2.43.0