diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index fca71acc..603a72ea 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -209,8 +209,12 @@ void ThermalController::performControlOperation() { } else { transitionWhenHeatersOffCycles++; } - } else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) { - performThermalModuleCtrl(heaterSwitchStateArray); + } else if (mode != MODE_OFF) { + if (not tcsBrdShortlyUnavailable) { + performThermalModuleCtrl(heaterSwitchStateArray); + } + heaterTransitionControl(heaterSwitchStateArray); + heaterMaxDurationControl(heaterSwitchStateArray); } } @@ -1586,9 +1590,8 @@ void ThermalController::performThermalModuleCtrl(const HeaterSwitchStates& heate eBandTooHotFlag = false; } } - - heaterTransitionControl(heaterSwitchStates); } + void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { if (selectAndReadSensorTemp(htrCtx)) { if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { @@ -1613,6 +1616,7 @@ bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) { sensors[i].second > SANITY_LIMIT_LOWER_TEMP and sensors[i].second < SANITY_LIMIT_UPPER_TEMP) { sensorTemp = sensors[i].second; + currentSensorIndex = i; thermalStates[thermalComponent].errorCounter = 0; return true; } @@ -1689,7 +1693,6 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { 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. @@ -1754,6 +1757,11 @@ void ThermalController::heaterTransitionControl(const HeaterSwitchStates& curren for (unsigned i = 0; i < 7; i++) { if (heaterStates[i].switchTransition) { if (currentHeaterStates[i] == heaterStates[i].target) { + // Required for max heat period control + if (currentHeaterStates[i] == HeaterHandler::SwitchState::ON) { + heaterStates[i].heaterOnPeriod.setTimeout(MAX_HEATER_ON_DURATIONS[i]); + heaterStates[i].heaterOnPeriod.resetTimer(); + } heaterStates[i].switchTransition = false; continue; } @@ -1765,6 +1773,26 @@ void ThermalController::heaterTransitionControl(const HeaterSwitchStates& curren } } } + +void ThermalController::heaterMaxDurationControl(const HeaterSwitchStates& currentHeaterStates) { + for (unsigned i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { + if (currentHeaterStates[i] == HeaterHandler::SwitchState::ON and + heaterStates[i].heaterOnPeriod.hasTimedOut()) { + heaterStates[i].switchTransition = false; + heaterStates[i].heaterSwitchControlCycles = 0; + heaterHandler.switchHeater(static_cast(i), HeaterHandler::SwitchState::OFF); + for (unsigned j = 0; j < thermalStates.size(); j++) { + if (thermalStates[j].heating and thermalStates[j].heaterSwitch == i) { + timeval currentTime; + Clock::getClockMonotonic(¤tTime); + thermalStates[j].heating = false; + thermalStates[j].heaterEndTime = currentTime.tv_sec; + } + } + } + } +} + uint32_t ThermalController::tempFloatToU32() const { auto sensorTempAsFloat = static_cast(sensorTemp); uint32_t tempRaw = 0; @@ -1799,6 +1827,11 @@ bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO void ThermalController::resetThermalStates() { for (auto& thermalState : thermalStates) { thermalState.heating = false; + thermalState.errorCounter = 0; + thermalState.heaterStartTime = 0; + thermalState.heaterEndTime = 0; + thermalState.sensorIndex = 0; + thermalState.heaterSwitch = heater::Switch::NUMBER_OF_SWITCHES; } } @@ -1809,6 +1842,9 @@ void ThermalController::heaterSwitchHelper(heater::Switch switchNr, Clock::getClockMonotonic(¤tTime); if (state == HeaterHandler::SwitchState::ON) { heaterHandler.switchHeater(switchNr, state); + heaterStates[switchNr].switchTransition = true; + thermalStates[componentIdx].sensorIndex = currentSensorIndex; + thermalStates[componentIdx].heaterSwitch = switchNr; thermalStates[componentIdx].heating = true; thermalStates[componentIdx].heaterStartTime = currentTime.tv_sec; } else { diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index 2518a13e..6695e7e7 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -48,8 +48,11 @@ struct TempLimits { struct ThermalState { uint8_t errorCounter; + // Which sensor is used for this component? + uint8_t sensorIndex = 0; // Is heating on for that thermal module? bool heating = false; + // Which switch is being used for heating the component 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. @@ -61,6 +64,7 @@ struct HeaterState { bool switchTransition; HeaterHandler::SwitchState target; uint8_t heaterSwitchControlCycles; + Countdown heaterOnPeriod; }; using HeaterSwitchStates = std::array; @@ -102,6 +106,25 @@ class ThermalController : public ExtendedControllerBase { static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160; + // 1 hour + static constexpr uint32_t MAX_HEATER_ON_DURATION_MS = 60 * 60 * 1000; + static constexpr uint32_t MAX_HEATER_ON_DURATIONS[8] = {// PLOC PROC board + MAX_HEATER_ON_DURATION_MS, + // PCDU PDU + MAX_HEATER_ON_DURATION_MS, + // ACS Board + MAX_HEATER_ON_DURATION_MS, + // OBC Board + MAX_HEATER_ON_DURATION_MS, + // Camera + MAX_HEATER_ON_DURATION_MS, + // STR + MAX_HEATER_ON_DURATION_MS, + // DRO + MAX_HEATER_ON_DURATION_MS, + // S-Band + MAX_HEATER_ON_DURATION_MS}; + ThermalController(object_id_t objectId, HeaterHandler& heater, const std::atomic_bool& tcsBoardShortUnavailable, bool pollPcdu1Tmp); virtual ~ThermalController(); @@ -256,6 +279,7 @@ class ThermalController : public ExtendedControllerBase { TempLimits scexBoardLimits = TempLimits(-60.0, -40.0, 80.0, 85.0, 150.0); double sensorTemp = INVALID_TEMPERATURE; + uint8_t currentSensorIndex = 0; ThermalComponents thermalComponent = NONE; bool redSwitchNrInUse = false; MessageQueueId_t camId = MessageQueueIF::NO_QUEUE; @@ -348,6 +372,7 @@ class ThermalController : public ExtendedControllerBase { void ctrlMpa(); void ctrlScexBoard(); void heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates); + void heaterMaxDurationControl(const HeaterSwitchStates& currentHeaterStates); void setMode(Mode_t mode, Submode_t submode); uint32_t tempFloatToU32() const; bool tooHotHandler(object_id_t object, bool& oneShotFlag); diff --git a/tmtc b/tmtc index c48f04ee..5785bbd0 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit c48f04eed5152f319b217870292968fb67b763d4 +Subproject commit 5785bbd0ccb045e072f347a5ff2265c610d3872c