diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index da508f33..4ff06fef 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1693,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].target = HeaterHandler::SwitchState::ON; } else { // Even if heater control is now allowed, we can update the state. thermalStates[thermalComponent].heating = false; @@ -1757,10 +1756,14 @@ void ThermalController::heaterTransitionControl(const HeaterSwitchStates& curren for (unsigned i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { if (heaterStates[i].switchTransition) { if (currentHeaterStates[i] == heaterStates[i].target) { - // Required for max heat period control + // Required for max heater period control if (currentHeaterStates[i] == HeaterHandler::SwitchState::ON) { heaterStates[i].heaterOnPeriod.setTimeout(MAX_HEATER_ON_DURATIONS[i]); heaterStates[i].heaterOnPeriod.resetTimer(); + } else { + // The heater might still be one for some thermal components, so cross-check + // those components + crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast(i)); } heaterStates[i].switchTransition = false; continue; @@ -1781,14 +1784,9 @@ void ThermalController::heaterMaxDurationControl(const HeaterSwitchStates& curre 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; - } - } + // The heater might still be one for some thermal components, so cross-check + // those components + crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast(i)); } } } @@ -1836,19 +1834,20 @@ void ThermalController::resetThermalStates() { } void ThermalController::heaterSwitchHelper(heater::Switch switchNr, - HeaterHandler::SwitchState state, + HeaterHandler::SwitchState targetState, unsigned componentIdx) { timeval currentTime; Clock::getClockMonotonic(¤tTime); - if (state == HeaterHandler::SwitchState::ON) { - heaterHandler.switchHeater(switchNr, state); + if (targetState == HeaterHandler::SwitchState::ON) { + heaterHandler.switchHeater(switchNr, targetState); + heaterStates[switchNr].target = HeaterHandler::SwitchState::ON; heaterStates[switchNr].switchTransition = true; thermalStates[componentIdx].sensorIndex = currentSensorIndex; thermalStates[componentIdx].heaterSwitch = switchNr; thermalStates[componentIdx].heating = true; thermalStates[componentIdx].heaterStartTime = currentTime.tv_sec; } else { - heaterHandler.switchHeater(switchNr, state); + heaterHandler.switchHeater(switchNr, targetState); thermalStates[componentIdx].heating = false; thermalStates[componentIdx].heaterEndTime = currentTime.tv_sec; } @@ -1873,6 +1872,18 @@ ThermalController::~ThermalController() { } } +void ThermalController::crossCheckHeaterStateOfComponentsWhenHeaterGoesOff( + heater::Switch switchIdx) { + for (unsigned j = 0; j < thermalStates.size(); j++) { + if (thermalStates[j].heating and thermalStates[j].heaterSwitch == switchIdx) { + timeval currentTime; + Clock::getClockMonotonic(¤tTime); + thermalStates[j].heating = false; + thermalStates[j].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 6695e7e7..021be00e 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -371,8 +371,22 @@ class ThermalController : public ExtendedControllerBase { void ctrlTx(); void ctrlMpa(); void ctrlScexBoard(); + + /** + * The transition of heaters might take some time. As long as a transition is + * going on, the TCS controller works in a reduced form. This function takes care + * of tracking transition and capturing their completion. + * @param currentHeaterStates + */ void heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates); + /** + * Control tasks to prevent heaters being on for prolonged periods. Ideally, this + * should never happen, but this task prevents bugs from causing heaters to stay on + * for a long time, which draws a lot of power. + * @param currentHeaterStates + */ void heaterMaxDurationControl(const HeaterSwitchStates& currentHeaterStates); + void crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(heater::Switch switchIdx); void setMode(Mode_t mode, Submode_t submode); uint32_t tempFloatToU32() const; bool tooHotHandler(object_id_t object, bool& oneShotFlag);