#include "ThermalController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Enabling this should trigger a special event which in turn should trigger a system reaction. #define LOWER_SYRLINKS_UPPER_LIMITS 0 #define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_PLOC_UPPER_LIMITS 0 #define LOWER_MGT_UPPER_LIMITS 0 #define LOWER_RW_UPPER_LIMITS 0 ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater, const std::atomic_bool& tcsBoardShortUnavailable, bool pollPcdu1Tmp) : ExtendedControllerBase(objectId), heaterHandler(heater), pollPcdu1Tmp(pollPcdu1Tmp), sensorTemperatures(this), susTemperatures(this), deviceTemperatures(this), heaterInfo(this), tcsCtrlInfo(this), imtqThermalSet(objects::IMTQ_HANDLER, ThermalStateCfg()), maxSet0PlocHspd(objects::RTD_0_IC3_PLOC_HEATSPREADER, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet1PlocMissionBrd(objects::RTD_1_IC4_PLOC_MISSIONBOARD, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet2PlCam(objects::RTD_2_IC5_4K_CAMERA, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet3DacHspd(objects::RTD_3_IC6_DAC_HEATSPREADER, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet4Str(objects::RTD_4_IC7_STARTRACKER, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet5Rw1MxMy(objects::RTD_5_IC8_RW1_MX_MY, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet6Dro(objects::RTD_6_IC9_DRO, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet7Scex(objects::RTD_7_IC10_SCEX, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet8X8(objects::RTD_8_IC11_X8, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet9Hpa(objects::RTD_9_IC12_HPA, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet10EbandTx(objects::RTD_10_IC13_PL_TX, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet11Mpa(objects::RTD_11_IC14_MPA, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet31865Set12(objects::RTD_12_IC15_ACU, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet13PlPcduHspd(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet14TcsBrd(objects::RTD_14_IC17_TCS_BOARD, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), maxSet15Imtq(objects::RTD_15_IC18_IMTQ, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), tmp1075SetTcs0(objects::TMP1075_HANDLER_TCS_0), tmp1075SetTcs1(objects::TMP1075_HANDLER_TCS_1), tmp1075SetPlPcdu0(objects::TMP1075_HANDLER_PLPCDU_0), tmp1075SetIfBoard(objects::TMP1075_HANDLER_IF_BOARD), susSet0(objects::SUS_0_N_LOC_XFYFZM_PT_XF), susSet1(objects::SUS_1_N_LOC_XBYFZM_PT_XB), susSet2(objects::SUS_2_N_LOC_XFYBZB_PT_YB), susSet3(objects::SUS_3_N_LOC_XFYBZF_PT_YF), susSet4(objects::SUS_4_N_LOC_XMYFZF_PT_ZF), susSet5(objects::SUS_5_N_LOC_XFYMZB_PT_ZB), susSet6(objects::SUS_6_R_LOC_XFYBZM_PT_XF), susSet7(objects::SUS_7_R_LOC_XBYBZM_PT_XB), 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), tcsBrdShortlyUnavailable(tcsBoardShortUnavailable) { if (pollPcdu1Tmp) { tmp1075SetPlPcdu1 = new TMP1075::Tmp1075Dataset(objects::TMP1075_HANDLER_PLPCDU_1); } resetSensorsArray(); } ReturnValue_t ThermalController::initialize() { auto* camSwitcher = ObjectManager::instance()->get(objects::CAM_SWITCHER); if (camSwitcher == nullptr) { return ObjectManagerIF::CHILD_INIT_FAILED; } camId = camSwitcher->getCommandQueue(); return ExtendedControllerBase::initialize(); } ReturnValue_t ThermalController::handleCommandMessage(CommandMessage* message) { return returnvalue::FAILED; } void ThermalController::performControlOperation() { #if OBSW_THREAD_TRACING == 1 trace::threadTrace(opCounter, "TCS Task"); #endif switch (internalState) { case InternalState::STARTUP: { initialCountdown.resetTimer(); internalState = InternalState::INITIAL_DELAY; return; } case InternalState::INITIAL_DELAY: { if (initialCountdown.hasTimedOut()) { sif::info << "Starting thermal control operations" << std::endl; internalState = InternalState::READY; break; } return; } case InternalState::READY: { break; } default: break; } if (cycles == 40) { bool changedLimits = false; #if LOWER_SYRLINKS_UPPER_LIMITS == 1 changedLimits = true; sBandTransceiverLimits.cutOffLimit = 0; sBandTransceiverLimits.opUpperLimit = 0; sBandTransceiverLimits.nopUpperLimit = 0; #endif #if LOWER_PLOC_UPPER_LIMITS == 1 changedLimits = true; plocMissionBoardLimits.cutOffLimit = 0; plocMissionBoardLimits.opUpperLimit = 0; plocMissionBoardLimits.nopUpperLimit = 0; #endif #if LOWER_EBAND_UPPER_LIMITS == 1 changedLimits = true; hpaLimits.cutOffLimit = 0; hpaLimits.opUpperLimit = 0; hpaLimits.nopUpperLimit = 0; #endif #if LOWER_MGT_UPPER_LIMITS == 1 changedLimits = true; mgtLimits.cutOffLimit = 0; mgtLimits.opUpperLimit = 0; mgtLimits.nopUpperLimit = 0; #endif #if LOWER_RW_UPPER_LIMITS == 1 changedLimits = true; rwLimits.cutOffLimit = 0; rwLimits.opUpperLimit = 0; rwLimits.nopUpperLimit = 0; #endif if (changedLimits) { sif::debug << "ThermalController: changing limits" << std::endl; } } if (not tcsBrdShortlyUnavailable) { { PoolReadGuard pg(&sensorTemperatures); if (pg.getReadResult() == returnvalue::OK) { copySensors(); } } } { PoolReadGuard pg(&susTemperatures); if (pg.getReadResult() == returnvalue::OK) { copySus(); } } { PoolReadGuard pg(&deviceTemperatures); if (pg.getReadResult() == returnvalue::OK) { copyDevices(); } } tcsCtrl::HeaterSwitchStates heaterSwitchStateArray{}; heaterHandler.getAllSwitchStates(heaterSwitchStateArray); { PoolReadGuard pg(&heaterInfo); std::memcpy(heaterInfo.heaterSwitchState.value, heaterSwitchStateArray.data(), 8); { PoolReadGuard pg2(¤tVecPdu2); if (pg.getReadResult() == returnvalue::OK and pg2.getReadResult() == returnvalue::OK) { heaterInfo.heaterCurrent.value = currentVecPdu2.value[PDU2::Channels::TCS_HEATER_IN]; } } } cycles++; if (transitionWhenHeatersOff) { bool allSwitchersOff = true; for (size_t idx = 0; idx < heaterSwitchStateArray.size(); idx++) { if (heaterSwitchStateArray[idx] != heater::SwitchState::OFF) { allSwitchersOff = false; // if heater still ON after 3 cycles, switch OFF again if (transitionWhenHeatersOffCycles == 3) { heaterHandler.switchHeater(static_cast(idx), heater::SwitchState::OFF); triggerEvent(tcsCtrl::HEATER_NOT_OFF_FOR_OFF_MODE); } } } if (allSwitchersOff or transitionWhenHeatersOffCycles == 6) { // Finish the transition transitionWhenHeatersOff = false; resetThermalStates(); setMode(targetMode, targetSubmode); } else { transitionWhenHeatersOffCycles++; } } else if (mode != MODE_OFF) { if (not tcsBrdShortlyUnavailable) { performThermalModuleCtrl(heaterSwitchStateArray); } heaterTransitionControl(heaterSwitchStateArray); heaterMaxDurationControl(heaterSwitchStateArray); // This dataset makes the TCS CTRL observable. PoolReadGuard pg(&tcsCtrlInfo); for (uint8_t i = 0; i < thermalStates.size(); i++) { tcsCtrlInfo.heatingOnVec[i] = thermalStates[i].heating; tcsCtrlInfo.sensorIdxUsedForTcsCtrl[i] = thermalStates[i].sensorIndex; tcsCtrlInfo.heaterSwitchIdx[i] = thermalStates[i].heaterSwitch; tcsCtrlInfo.heaterStartTimes[i] = thermalStates[i].heaterStartTime; tcsCtrlInfo.heaterEndTimes[i] = thermalStates[i].heaterEndTime; } } } ReturnValue_t ThermalController::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) { localDataPoolMap.emplace(tcsCtrl::SENSOR_PLOC_HEATSPREADER, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_PLOC_MISSIONBOARD, new PoolEntry({1.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_4K_CAMERA, new PoolEntry({2.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_DAC_HEATSPREADER, new PoolEntry({3.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_STARTRACKER, new PoolEntry({4.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_RW1, new PoolEntry({5.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_DRO, new PoolEntry({6.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_SCEX, new PoolEntry({7.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_X8, new PoolEntry({8.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_HPA, new PoolEntry({9.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_TX_MODUL, new PoolEntry({10.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_MPA, new PoolEntry({11.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_ACU, new PoolEntry({12.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_PLPCDU_HEATSPREADER, new PoolEntry({13.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_TCS_BOARD, new PoolEntry({14.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_MAGNETTORQUER, new PoolEntry({15.0})); localDataPoolMap.emplace(tcsCtrl::SENSOR_TMP1075_TCS_0, &tmp1075Tcs0); localDataPoolMap.emplace(tcsCtrl::SENSOR_TMP1075_TCS_1, &tmp1075Tcs1); localDataPoolMap.emplace(tcsCtrl::SENSOR_TMP1075_PLPCDU_0, &tmp1075PlPcdu0); localDataPoolMap.emplace(tcsCtrl::SENSOR_TMP1075_PLPCDU_1, &tmp1075PlPcdu1); localDataPoolMap.emplace(tcsCtrl::SENSOR_TMP1075_IF_BOARD, &tmp1075IfBrd); localDataPoolMap.emplace(tcsCtrl::SUS_0_N_LOC_XFYFZM_PT_XF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_6_R_LOC_XFYBZM_PT_XF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_1_N_LOC_XBYFZM_PT_XB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_7_R_LOC_XBYBZM_PT_XB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_2_N_LOC_XFYBZB_PT_YB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_8_R_LOC_XBYBZB_PT_YB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_3_N_LOC_XFYBZF_PT_YF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_9_R_LOC_XBYBZB_PT_YF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_4_N_LOC_XMYFZF_PT_ZF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_10_N_LOC_XMYBZF_PT_ZF, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_5_N_LOC_XFYMZB_PT_ZB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::SUS_11_R_LOC_XBYMZB_PT_ZB, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::COMPONENT_RW, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_Q7S, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_1, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_2, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_3, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_4, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_RW1, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_RW2, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_RW3, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_RW4, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_STAR_TRACKER, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_SYRLINKS_POWER_AMPLIFIER, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_SYRLINKS_BASEBAND_BOARD, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_MGT, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_ACU, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_PDU1, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_PDU2, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_1_P60DOCK, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_2_P60DOCK, new PoolEntry({0})); localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_0_SIDE_A, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_1_SIDE_A, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_2_SIDE_B, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_3_SIDE_B, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_MGM_0_SIDE_A, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_MGM_2_SIDE_B, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::TEMP_ADC_PAYLOAD_PCDU, new PoolEntry({0.0})); localDataPoolMap.emplace(tcsCtrl::HEATER_SWITCH_LIST, &heaterSwitchStates); localDataPoolMap.emplace(tcsCtrl::HEATER_CURRENT, &heaterCurrent); localDataPoolMap.emplace(tcsCtrl::HEATER_ON_FOR_COMPONENT_VEC, &tcsCtrlHeaterOn); localDataPoolMap.emplace(tcsCtrl::SENSOR_USED_FOR_TCS_CTRL, &tcsCtrlSensorIdx); localDataPoolMap.emplace(tcsCtrl::HEATER_IDX_USED_FOR_TCS_CTRL, &tcsCtrlHeaterIdx); localDataPoolMap.emplace(tcsCtrl::HEATER_START_TIME, &tcsCtrlStartTimes); localDataPoolMap.emplace(tcsCtrl::HEATER_END_TIME, &tcsCtrlEndTimes); bool enableHkSets = false; #if OBSW_ENABLE_PERIODIC_HK == 1 enableHkSets = true; #endif poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(sensorTemperatures.getSid(), enableHkSets, 120.0)); poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(susTemperatures.getSid(), enableHkSets, 240.0)); poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(deviceTemperatures.getSid(), enableHkSets, 120.0)); poolManager.subscribeForDiagPeriodicPacket( subdp::DiagnosticsHkPeriodicParams(heaterInfo.getSid(), enableHkSets, 120.0)); poolManager.subscribeForRegularPeriodicPacket( subdp::RegularHkPeriodicParams(tcsCtrlInfo.getSid(), enableHkSets, 120.0)); return returnvalue::OK; } LocalPoolDataSetBase* ThermalController::getDataSetHandle(sid_t sid) { switch (sid.ownerSetId) { case tcsCtrl::SENSOR_TEMPERATURES: return &sensorTemperatures; case tcsCtrl::SUS_TEMPERATURES: return &susTemperatures; case tcsCtrl::DEVICE_TEMPERATURES: return &deviceTemperatures; case tcsCtrl::HEATER_SET: return &heaterInfo; case tcsCtrl::TCS_CTRL_INFO: return &tcsCtrlInfo; default: return nullptr; } } 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; } return returnvalue::OK; } void ThermalController::copySensors() { { PoolReadGuard pg0(&maxSet0PlocHspd, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg0.getReadResult() == returnvalue::OK) { sensorTemperatures.plocHeatspreader.value = maxSet0PlocHspd.temperatureCelcius.value; sensorTemperatures.plocHeatspreader.setValid(maxSet0PlocHspd.temperatureCelcius.isValid()); if (not sensorTemperatures.plocHeatspreader.isValid()) { sensorTemperatures.plocHeatspreader.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg1(&maxSet1PlocMissionBrd, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg1.getReadResult() == returnvalue::OK) { sensorTemperatures.plocMissionboard.value = maxSet1PlocMissionBrd.temperatureCelcius.value; sensorTemperatures.plocMissionboard.setValid( maxSet1PlocMissionBrd.temperatureCelcius.isValid()); if (not sensorTemperatures.plocMissionboard.isValid()) { sensorTemperatures.plocMissionboard.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg2(&maxSet2PlCam, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg2.getReadResult() == returnvalue::OK) { sensorTemperatures.payload4kCamera.value = maxSet2PlCam.temperatureCelcius.value; sensorTemperatures.payload4kCamera.setValid(maxSet2PlCam.temperatureCelcius.isValid()); if (not sensorTemperatures.payload4kCamera.isValid()) { sensorTemperatures.payload4kCamera.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg3(&maxSet3DacHspd, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg3.getReadResult() == returnvalue::OK) { sensorTemperatures.dacHeatspreader.value = maxSet3DacHspd.temperatureCelcius.value; sensorTemperatures.dacHeatspreader.setValid(maxSet3DacHspd.temperatureCelcius.isValid()); if (not sensorTemperatures.dacHeatspreader.isValid()) { sensorTemperatures.dacHeatspreader.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg4(&maxSet4Str, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg4.getReadResult() == returnvalue::OK) { sensorTemperatures.startracker.value = maxSet4Str.temperatureCelcius.value; sensorTemperatures.startracker.setValid(maxSet4Str.temperatureCelcius.isValid()); if (not sensorTemperatures.startracker.isValid()) { sensorTemperatures.startracker.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg5(&maxSet5Rw1MxMy, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg5.getReadResult() == returnvalue::OK) { sensorTemperatures.rw1.value = maxSet5Rw1MxMy.temperatureCelcius.value; sensorTemperatures.rw1.setValid(maxSet5Rw1MxMy.temperatureCelcius.isValid()); if (not sensorTemperatures.rw1.isValid()) { sensorTemperatures.rw1.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg6(&maxSet6Dro, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg6.getReadResult() == returnvalue::OK) { sensorTemperatures.dro.value = maxSet6Dro.temperatureCelcius.value; sensorTemperatures.dro.setValid(maxSet6Dro.temperatureCelcius.isValid()); if (not sensorTemperatures.dro.isValid()) { sensorTemperatures.dro.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg7(&maxSet7Scex, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg7.getReadResult() == returnvalue::OK) { sensorTemperatures.scex.value = maxSet7Scex.temperatureCelcius.value; sensorTemperatures.scex.setValid(maxSet7Scex.temperatureCelcius.isValid()); if (not sensorTemperatures.scex.isValid()) { sensorTemperatures.scex.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg8(&maxSet8X8, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg8.getReadResult() == returnvalue::OK) { sensorTemperatures.x8.value = maxSet8X8.temperatureCelcius.value; sensorTemperatures.x8.setValid(maxSet8X8.temperatureCelcius.isValid()); if (not sensorTemperatures.x8.isValid()) { sensorTemperatures.x8.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg9(&maxSet9Hpa, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg9.getReadResult() == returnvalue::OK) { sensorTemperatures.hpa.value = maxSet9Hpa.temperatureCelcius.value; sensorTemperatures.hpa.setValid(maxSet9Hpa.temperatureCelcius.isValid()); if (not sensorTemperatures.hpa.isValid()) { sensorTemperatures.hpa.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg10(&maxSet10EbandTx, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg10.getReadResult() == returnvalue::OK) { sensorTemperatures.eBandTx.value = maxSet10EbandTx.temperatureCelcius.value; sensorTemperatures.eBandTx.setValid(maxSet10EbandTx.temperatureCelcius.isValid()); if (not sensorTemperatures.eBandTx.isValid()) { sensorTemperatures.eBandTx.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg11(&maxSet11Mpa, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg11.getReadResult() == returnvalue::OK) { sensorTemperatures.mpa.value = maxSet11Mpa.temperatureCelcius.value; sensorTemperatures.mpa.setValid(maxSet11Mpa.temperatureCelcius.isValid()); if (not sensorTemperatures.mpa.isValid()) { sensorTemperatures.mpa.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg12(&maxSet31865Set12, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg12.getReadResult() == returnvalue::OK) { sensorTemperatures.acu.value = maxSet31865Set12.temperatureCelcius.value; sensorTemperatures.acu.setValid(maxSet31865Set12.temperatureCelcius.isValid()); if (not sensorTemperatures.acu.isValid()) { sensorTemperatures.acu.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg13(&maxSet13PlPcduHspd, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg13.getReadResult() == returnvalue::OK) { sensorTemperatures.plpcduHeatspreader.value = maxSet13PlPcduHspd.temperatureCelcius.value; sensorTemperatures.plpcduHeatspreader.setValid( maxSet13PlPcduHspd.temperatureCelcius.isValid()); if (not sensorTemperatures.plpcduHeatspreader.isValid()) { sensorTemperatures.plpcduHeatspreader.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg14(&maxSet14TcsBrd, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg14.getReadResult() == returnvalue::OK) { sensorTemperatures.tcsBoard.value = maxSet14TcsBrd.temperatureCelcius.value; sensorTemperatures.tcsBoard.setValid(maxSet14TcsBrd.temperatureCelcius.isValid()); if (not sensorTemperatures.tcsBoard.isValid()) { sensorTemperatures.tcsBoard.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg15(&maxSet15Imtq, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg15.getReadResult() == returnvalue::OK) { sensorTemperatures.mgt.value = maxSet15Imtq.temperatureCelcius.value; sensorTemperatures.mgt.setValid(maxSet15Imtq.temperatureCelcius.isValid()); if (not sensorTemperatures.mgt.isValid()) { sensorTemperatures.mgt.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg(&tmp1075SetTcs0, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { sensorTemperatures.tmp1075Tcs0.value = tmp1075SetTcs0.temperatureCelcius.value; sensorTemperatures.tmp1075Tcs0.setValid(tmp1075SetTcs0.temperatureCelcius.isValid()); if (not tmp1075SetTcs0.temperatureCelcius.isValid()) { sensorTemperatures.tmp1075Tcs0.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg(&tmp1075SetTcs1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { sensorTemperatures.tmp1075Tcs1.value = tmp1075SetTcs1.temperatureCelcius.value; sensorTemperatures.tmp1075Tcs1.setValid(tmp1075SetTcs1.temperatureCelcius.isValid()); if (not tmp1075SetTcs1.temperatureCelcius.isValid()) { sensorTemperatures.tmp1075Tcs1.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg(&tmp1075SetPlPcdu0, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { sensorTemperatures.tmp1075PlPcdu0.value = tmp1075SetPlPcdu0.temperatureCelcius.value; sensorTemperatures.tmp1075PlPcdu0.setValid(tmp1075SetPlPcdu0.temperatureCelcius.isValid()); if (not tmp1075SetPlPcdu0.temperatureCelcius.isValid()) { sensorTemperatures.tmp1075PlPcdu0.value = INVALID_TEMPERATURE; } } } // damaged on FM, and no dummies for now if (pollPcdu1Tmp) { { PoolReadGuard pg(tmp1075SetPlPcdu1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { sensorTemperatures.tmp1075PlPcdu1.value = tmp1075SetPlPcdu1->temperatureCelcius.value; sensorTemperatures.tmp1075PlPcdu1.setValid(tmp1075SetPlPcdu1->temperatureCelcius.isValid()); if (not tmp1075SetPlPcdu1->temperatureCelcius.isValid()) { sensorTemperatures.tmp1075PlPcdu1.value = INVALID_TEMPERATURE; } } } } { PoolReadGuard pg(&tmp1075SetIfBoard, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { sensorTemperatures.tmp1075IfBrd.value = tmp1075SetIfBoard.temperatureCelcius.value; sensorTemperatures.tmp1075IfBrd.setValid(tmp1075SetIfBoard.temperatureCelcius.isValid()); if (not tmp1075SetIfBoard.temperatureCelcius.isValid()) { sensorTemperatures.tmp1075IfBrd.value = INVALID_TEMPERATURE; } } } } void ThermalController::copySus() { { PoolReadGuard pg0(&susSet0, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg0.getReadResult() == returnvalue::OK) { susTemperatures.sus_0_n_loc_xfyfzm_pt_xf.value = susSet0.tempC.value; susTemperatures.sus_0_n_loc_xfyfzm_pt_xf.setValid(susSet0.tempC.isValid()); if (not susTemperatures.sus_0_n_loc_xfyfzm_pt_xf.isValid()) { susTemperatures.sus_0_n_loc_xfyfzm_pt_xf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg1(&susSet1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg1.getReadResult() == returnvalue::OK) { susTemperatures.sus_6_r_loc_xfybzm_pt_xf.value = susSet1.tempC.value; susTemperatures.sus_6_r_loc_xfybzm_pt_xf.setValid(susSet1.tempC.isValid()); if (not susTemperatures.sus_6_r_loc_xfybzm_pt_xf.isValid()) { susTemperatures.sus_6_r_loc_xfybzm_pt_xf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg2(&susSet2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg2.getReadResult() == returnvalue::OK) { susTemperatures.sus_1_n_loc_xbyfzm_pt_xb.value = susSet2.tempC.value; susTemperatures.sus_1_n_loc_xbyfzm_pt_xb.setValid(susSet2.tempC.isValid()); if (not susTemperatures.sus_1_n_loc_xbyfzm_pt_xb.isValid()) { susTemperatures.sus_1_n_loc_xbyfzm_pt_xb.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg3(&susSet3, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg3.getReadResult() == returnvalue::OK) { susTemperatures.sus_7_r_loc_xbybzm_pt_xb.value = susSet3.tempC.value; susTemperatures.sus_7_r_loc_xbybzm_pt_xb.setValid(susSet3.tempC.isValid()); if (not susTemperatures.sus_7_r_loc_xbybzm_pt_xb.isValid()) { susTemperatures.sus_7_r_loc_xbybzm_pt_xb.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg4(&susSet4, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg4.getReadResult() == returnvalue::OK) { susTemperatures.sus_2_n_loc_xfybzb_pt_yb.value = susSet4.tempC.value; susTemperatures.sus_2_n_loc_xfybzb_pt_yb.setValid(susSet4.tempC.isValid()); if (not susTemperatures.sus_2_n_loc_xfybzb_pt_yb.isValid()) { susTemperatures.sus_2_n_loc_xfybzb_pt_yb.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg5(&susSet5, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg5.getReadResult() == returnvalue::OK) { susTemperatures.sus_8_r_loc_xbybzb_pt_yb.value = susSet5.tempC.value; susTemperatures.sus_8_r_loc_xbybzb_pt_yb.setValid(susSet5.tempC.isValid()); if (not susTemperatures.sus_8_r_loc_xbybzb_pt_yb.isValid()) { susTemperatures.sus_8_r_loc_xbybzb_pt_yb.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg6(&susSet6, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg6.getReadResult() == returnvalue::OK) { susTemperatures.sus_3_n_loc_xfybzf_pt_yf.value = susSet6.tempC.value; susTemperatures.sus_3_n_loc_xfybzf_pt_yf.setValid(susSet6.tempC.isValid()); if (not susTemperatures.sus_3_n_loc_xfybzf_pt_yf.isValid()) { susTemperatures.sus_3_n_loc_xfybzf_pt_yf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg7(&susSet7, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg7.getReadResult() == returnvalue::OK) { susTemperatures.sus_9_r_loc_xbybzb_pt_yf.value = susSet7.tempC.value; susTemperatures.sus_9_r_loc_xbybzb_pt_yf.setValid(susSet7.tempC.isValid()); if (not susTemperatures.sus_9_r_loc_xbybzb_pt_yf.isValid()) { susTemperatures.sus_9_r_loc_xbybzb_pt_yf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg8(&susSet8, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg8.getReadResult() == returnvalue::OK) { susTemperatures.sus_4_n_loc_xmyfzf_pt_zf.value = susSet8.tempC.value; susTemperatures.sus_4_n_loc_xmyfzf_pt_zf.setValid(susSet8.tempC.isValid()); if (not susTemperatures.sus_4_n_loc_xmyfzf_pt_zf.isValid()) { susTemperatures.sus_4_n_loc_xmyfzf_pt_zf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg9(&susSet9, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg9.getReadResult() == returnvalue::OK) { susTemperatures.sus_10_n_loc_xmybzf_pt_zf.value = susSet9.tempC.value; susTemperatures.sus_10_n_loc_xmybzf_pt_zf.setValid(susSet9.tempC.isValid()); if (not susTemperatures.sus_10_n_loc_xmybzf_pt_zf.isValid()) { susTemperatures.sus_10_n_loc_xmybzf_pt_zf.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg10(&susSet10, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg10.getReadResult() == returnvalue::OK) { susTemperatures.sus_5_n_loc_xfymzb_pt_zb.value = susSet10.tempC.value; susTemperatures.sus_5_n_loc_xfymzb_pt_zb.setValid(susSet10.tempC.isValid()); if (not susTemperatures.sus_5_n_loc_xfymzb_pt_zb.isValid()) { susTemperatures.sus_5_n_loc_xfymzb_pt_zb.value = INVALID_TEMPERATURE; } } } { PoolReadGuard pg11(&susSet11, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg11.getReadResult() == returnvalue::OK) { susTemperatures.sus_11_r_loc_xbymzb_pt_zb.value = susSet11.tempC.value; susTemperatures.sus_11_r_loc_xbymzb_pt_zb.setValid(susSet11.tempC.isValid()); if (not susTemperatures.sus_11_r_loc_xbymzb_pt_zb.isValid()) { susTemperatures.sus_11_r_loc_xbymzb_pt_zb.value = INVALID_TEMPERATURE; } } } } void ThermalController::copyDevices() { { PoolReadGuard pg(&tempQ7s, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() == returnvalue::OK) { deviceTemperatures.q7s = tempQ7s; deviceTemperatures.q7s.setValid(tempQ7s.isValid()); } else { deviceTemperatures.q7s.setValid(false); deviceTemperatures.q7s = static_cast(INVALID_TEMPERATURE); } } { PoolReadGuard pg(&battTemp1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read battery temperature 1" << std::endl; deviceTemperatures.batteryTemp1.setValid(false); deviceTemperatures.batteryTemp1 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.batteryTemp1 = battTemp1; deviceTemperatures.batteryTemp1.setValid(battTemp1.isValid()); } } { PoolReadGuard pg(&battTemp2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read battery temperature 2" << std::endl; deviceTemperatures.batteryTemp2.setValid(false); deviceTemperatures.batteryTemp2 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.batteryTemp2 = battTemp2; deviceTemperatures.batteryTemp2.setValid(battTemp2.isValid()); } } { PoolReadGuard pg(&battTemp3, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read battery temperature 3" << std::endl; deviceTemperatures.batteryTemp3.setValid(false); deviceTemperatures.batteryTemp3 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.batteryTemp3 = battTemp3; deviceTemperatures.batteryTemp3.setValid(battTemp3.isValid()); } } { PoolReadGuard pg(&battTemp4, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read battery temperature 4" << std::endl; deviceTemperatures.batteryTemp4.setValid(false); deviceTemperatures.batteryTemp4 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.batteryTemp4 = battTemp4; deviceTemperatures.batteryTemp4.setValid(battTemp4.isValid()); } } { PoolReadGuard pg(&tempRw1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read reaction wheel 1 temperature" << std::endl; deviceTemperatures.rw1.setValid(false); deviceTemperatures.rw1 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.rw1.setValid(tempRw1.isValid()); deviceTemperatures.rw1 = tempRw1; } } { PoolReadGuard pg(&tempRw2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read reaction wheel 2 temperature" << std::endl; deviceTemperatures.rw2.setValid(false); deviceTemperatures.rw2 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.rw2.setValid(tempRw2.isValid()); deviceTemperatures.rw2 = tempRw2; } } { PoolReadGuard pg(&tempRw3, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read reaction wheel 3 temperature" << std::endl; deviceTemperatures.rw3.setValid(false); deviceTemperatures.rw3 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.rw3.setValid(tempRw3.isValid()); deviceTemperatures.rw3 = tempRw3; } } { PoolReadGuard pg(&tempRw4, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read reaction wheel 4 temperature" << std::endl; deviceTemperatures.rw4.setValid(false); deviceTemperatures.rw4 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.rw4.setValid(tempRw4.isValid()); deviceTemperatures.rw4 = tempRw4; } } { PoolReadGuard pg(&tempStartracker, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read startracker temperature" << std::endl; deviceTemperatures.startracker.setValid(false); deviceTemperatures.startracker = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.startracker.setValid(tempStartracker.isValid()); deviceTemperatures.startracker = tempStartracker; } } { PoolReadGuard pg(&tempSyrlinksPowerAmplifier, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read syrlinks power amplifier temperature" << std::endl; deviceTemperatures.syrlinksPowerAmplifier.setValid(false); deviceTemperatures.syrlinksPowerAmplifier = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.syrlinksPowerAmplifier.setValid(tempSyrlinksPowerAmplifier.isValid()); deviceTemperatures.syrlinksPowerAmplifier = tempSyrlinksPowerAmplifier; } } { PoolReadGuard pg(&tempSyrlinksBasebandBoard, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read syrlinks baseband board temperature" << std::endl; deviceTemperatures.syrlinksBasebandBoard.setValid(false); deviceTemperatures.syrlinksBasebandBoard = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.syrlinksBasebandBoard.setValid(tempSyrlinksBasebandBoard.isValid()); deviceTemperatures.syrlinksBasebandBoard = tempSyrlinksBasebandBoard; } } { PoolReadGuard pg(&tempMgt, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read MGT temperature" << std::endl; deviceTemperatures.mgt.setValid(false); deviceTemperatures.mgt = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.mgt.setValid(tempMgt.isValid()); deviceTemperatures.mgt = tempMgt; } } { PoolReadGuard pg(&tempAcu, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read ACU temperatures" << std::endl; deviceTemperatures.acu.setValid(false); deviceTemperatures.acu[0] = static_cast(INVALID_TEMPERATURE); deviceTemperatures.acu[1] = static_cast(INVALID_TEMPERATURE); deviceTemperatures.acu[2] = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.acu.setValid(tempAcu.isValid()); deviceTemperatures.acu = tempAcu; } } { PoolReadGuard pg(&tempPdu1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read PDU1 temperature" << std::endl; deviceTemperatures.pdu1.setValid(false); deviceTemperatures.pdu1 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.pdu1.setValid(tempPdu1.isValid()); deviceTemperatures.pdu1 = tempPdu1; } } { PoolReadGuard pg(&tempPdu2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read PDU2 temperature" << std::endl; deviceTemperatures.pdu2.setValid(false); deviceTemperatures.pdu2 = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.pdu2.setValid(tempPdu2.isValid()); deviceTemperatures.pdu2 = tempPdu2; } } { PoolReadGuard pg(&temp1P60dock, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read P60 dock temperature 1" << std::endl; deviceTemperatures.temp1P60dock.setValid(false); deviceTemperatures.temp1P60dock = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.temp1P60dock.setValid(temp1P60dock.isValid()); deviceTemperatures.temp1P60dock = temp1P60dock; } } { PoolReadGuard pg(&temp2P60dock, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read P60 dock temperature 2" << std::endl; deviceTemperatures.temp2P60dock.setValid(false); deviceTemperatures.temp2P60dock = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.temp2P60dock.setValid(temp2P60dock.isValid()); deviceTemperatures.temp2P60dock = temp2P60dock; } } { PoolReadGuard pg(&tempGyro0, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read gyro 0 temperature" << std::endl; deviceTemperatures.gyro0SideA.setValid(false); deviceTemperatures.gyro0SideA = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.gyro0SideA.setValid(tempGyro0.isValid()); deviceTemperatures.gyro0SideA = tempGyro0; } } { PoolReadGuard pg(&tempGyro1, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read gyro 1 temperature" << std::endl; deviceTemperatures.gyro1SideA.setValid(false); deviceTemperatures.gyro1SideA = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.gyro1SideA.setValid(tempGyro1.isValid()); deviceTemperatures.gyro1SideA = tempGyro1; } } { PoolReadGuard pg(&tempGyro2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read gyro 2 temperature" << std::endl; deviceTemperatures.gyro2SideB.setValid(false); deviceTemperatures.gyro2SideB = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.gyro2SideB.setValid(tempGyro2.isValid()); deviceTemperatures.gyro2SideB = tempGyro2; } } { PoolReadGuard pg(&tempGyro3, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read gyro 3 temperature" << std::endl; deviceTemperatures.gyro3SideB.setValid(false); deviceTemperatures.gyro3SideB = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.gyro3SideB.setValid(tempGyro3.isValid()); deviceTemperatures.gyro3SideB = tempGyro3; } } { PoolReadGuard pg(&tempMgm0, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read MGM 0 temperature" << std::endl; deviceTemperatures.mgm0SideA.setValid(false); deviceTemperatures.mgm0SideA = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.mgm0SideA.setValid(tempMgm0.isValid()); deviceTemperatures.mgm0SideA = tempMgm0; } } { PoolReadGuard pg(&tempMgm2, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read MGM 2 temperature" << std::endl; deviceTemperatures.mgm2SideB.setValid(false); deviceTemperatures.mgm2SideB = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.mgm2SideB.setValid(tempMgm2.isValid()); deviceTemperatures.mgm2SideB = tempMgm2; } } { PoolReadGuard pg(&tempAdcPayloadPcdu, MutexIF::TimeoutType::WAITING, MUTEX_TIMEOUT); if (pg.getReadResult() != returnvalue::OK) { sif::warning << "ThermalController: Failed to read payload PCDU ADC temperature" << std::endl; deviceTemperatures.adcPayloadPcdu.setValid(false); deviceTemperatures.adcPayloadPcdu = static_cast(INVALID_TEMPERATURE); } else { deviceTemperatures.adcPayloadPcdu.setValid(tempAdcPayloadPcdu.isValid()); deviceTemperatures.adcPayloadPcdu = tempAdcPayloadPcdu; } } } void ThermalController::ctrlAcsBoard() { heater::Switch switchNr = heater::HEATER_2_ACS_BRD; heater::Switch redSwitchNr = heater::HEATER_3_OBC_BRD; // A side ctrlCtx.thermalComponent = tcsCtrl::ACS_BOARD; sensors[0].first = deviceTemperatures.gyro0SideA.isValid(); sensors[0].second = deviceTemperatures.gyro0SideA.value; sensors[1].first = deviceTemperatures.gyro2SideB.isValid(); sensors[1].second = deviceTemperatures.gyro2SideB.value; sensors[2].first = deviceTemperatures.mgm0SideA.isValid(); sensors[2].second = deviceTemperatures.mgm0SideA.value; sensors[3].first = deviceTemperatures.mgm2SideB.isValid(); sensors[3].second = deviceTemperatures.mgm2SideB.value; sensors[4].first = sensorTemperatures.tcsBoard.isValid(); sensors[4].second = sensorTemperatures.tcsBoard.value; numSensors = 5; { HeaterContext htrCtx(switchNr, redSwitchNr, acsBoardLimits); if (selectAndReadSensorTemp(htrCtx)) { if (chooseHeater(switchNr, redSwitchNr)) { checkLimitsAndCtrlHeater(htrCtx); } resetSensorsArray(); return; } } resetSensorsArray(); // B side sensors[0].first = deviceTemperatures.gyro2SideB.isValid(); sensors[0].second = deviceTemperatures.gyro2SideB.value; sensors[1].first = deviceTemperatures.mgm2SideB.isValid(); sensors[1].second = deviceTemperatures.mgm2SideB.value; sensors[2].first = deviceTemperatures.gyro3SideB.isValid(); sensors[2].second = deviceTemperatures.gyro3SideB.value; sensors[3].first = sensorTemperatures.tcsBoard.isValid(); sensors[3].second = sensorTemperatures.tcsBoard.value; numSensors = 4; { HeaterContext htrCtx(switchNr, redSwitchNr, acsBoardLimits); if (selectAndReadSensorTemp(htrCtx)) { if (chooseHeater(switchNr, redSwitchNr)) { checkLimitsAndCtrlHeater(htrCtx); } } else { if (chooseHeater(switchNr, redSwitchNr)) { if (heaterHandler.getSwitchState(switchNr)) { if (submode != SUBMODE_NO_HEATER_CTRL) { heaterSwitchHelper(switchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); } } } } } resetSensorsArray(); } void ThermalController::ctrlMgt() { ctrlCtx.thermalComponent = tcsCtrl::MGT; sensors[0].first = sensorTemperatures.mgt.isValid(); sensors[0].second = sensorTemperatures.mgt.value; sensors[1].first = deviceTemperatures.mgt.isValid(); sensors[1].second = deviceTemperatures.mgt.value; sensors[2].first = sensorTemperatures.plpcduHeatspreader.isValid(); sensors[2].second = sensorTemperatures.plpcduHeatspreader.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_2_ACS_BRD, heater::HEATER_1_PCDU_PDU, mgtLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.mgtTooHotFlag) { triggerEvent(tcsCtrl::MGT_OVERHEATING, tempFloatToU32()); tooHotFlags.mgtTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.mgtTooHotFlag = false; } } void ThermalController::ctrlRw() { Event eventToTrigger = 0; bool oneIsAboveLimit = false; std::array sensorTemps{}; // RW1 ctrlCtx.thermalComponent = tcsCtrl::RW; sensors[0].first = sensorTemperatures.rw1.isValid(); sensors[0].second = sensorTemperatures.rw1.value; sensors[1].first = deviceTemperatures.rw1.isValid(); sensors[1].second = deviceTemperatures.rw1.value; sensors[2].first = deviceTemperatures.rw4.isValid(); sensors[2].second = deviceTemperatures.rw4.value; sensors[3].first = sensorTemperatures.dro.isValid(); sensors[3].second = sensorTemperatures.dro.value; numSensors = 4; { HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_6_DRO, rwLimits); ctrlComponentTemperature(htrCtx); sensorTemps[0] = tempFloatToU32(); if (ctrlCtx.componentAboveUpperLimit) { oneIsAboveLimit = true; eventToTrigger = ctrlCtx.overHeatEventToTrigger; } } // RW2 ctrlCtx.thermalComponent = tcsCtrl::RW; sensors[0].first = deviceTemperatures.rw2.isValid(); sensors[0].second = deviceTemperatures.rw2.value; sensors[1].first = deviceTemperatures.rw3.isValid(); sensors[1].second = deviceTemperatures.rw3.value; sensors[2].first = sensorTemperatures.rw1.isValid(); sensors[2].second = sensorTemperatures.rw1.value; sensors[3].first = sensorTemperatures.dro.isValid(); sensors[3].second = sensorTemperatures.dro.value; numSensors = 4; { HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_6_DRO, rwLimits); ctrlComponentTemperature(htrCtx); sensorTemps[1] = tempFloatToU32(); if (ctrlCtx.componentAboveUpperLimit) { oneIsAboveLimit = true; if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) { eventToTrigger = ctrlCtx.overHeatEventToTrigger; } } } // RW3 ctrlCtx.thermalComponent = tcsCtrl::RW; sensors[0].first = deviceTemperatures.rw3.isValid(); sensors[0].second = deviceTemperatures.rw3.value; sensors[1].first = deviceTemperatures.rw4.isValid(); sensors[1].second = deviceTemperatures.rw4.value; sensors[2].first = sensorTemperatures.rw1.isValid(); sensors[2].second = sensorTemperatures.rw1.value; sensors[3].first = sensorTemperatures.dro.isValid(); sensors[3].second = sensorTemperatures.dro.value; numSensors = 4; { HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_6_DRO, rwLimits); ctrlComponentTemperature(htrCtx); sensorTemps[2] = tempFloatToU32(); if (ctrlCtx.componentAboveUpperLimit) { oneIsAboveLimit = true; if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) { eventToTrigger = ctrlCtx.overHeatEventToTrigger; } } } // RW4 ctrlCtx.thermalComponent = tcsCtrl::RW; sensors[0].first = deviceTemperatures.rw4.isValid(); sensors[0].second = deviceTemperatures.rw4.value; sensors[1].first = deviceTemperatures.rw1.isValid(); sensors[1].second = deviceTemperatures.rw1.value; sensors[2].first = sensorTemperatures.rw1.isValid(); sensors[2].second = sensorTemperatures.rw1.value; sensors[3].first = sensorTemperatures.dro.isValid(); sensors[3].second = sensorTemperatures.dro.value; numSensors = 4; { HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_6_DRO, rwLimits); ctrlComponentTemperature(htrCtx); sensorTemps[3] = tempFloatToU32(); if (ctrlCtx.componentAboveUpperLimit) { oneIsAboveLimit = true; if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) { eventToTrigger = ctrlCtx.overHeatEventToTrigger; } } } if (oneIsAboveLimit and not tooHotFlags.rwTooHotFlag) { EventManagerIF::triggerEvent(objects::RW1, eventToTrigger, sensorTemps[0]); EventManagerIF::triggerEvent(objects::RW2, eventToTrigger, sensorTemps[1]); EventManagerIF::triggerEvent(objects::RW3, eventToTrigger, sensorTemps[2]); EventManagerIF::triggerEvent(objects::RW4, eventToTrigger, sensorTemps[3]); tooHotFlags.rwTooHotFlag = true; } else if (not oneIsAboveLimit) { tooHotFlags.rwTooHotFlag = false; } } void ThermalController::ctrlStr() { ctrlCtx.thermalComponent = tcsCtrl::STR; sensors[0].first = sensorTemperatures.startracker.isValid(); sensors[0].second = sensorTemperatures.startracker.value; sensors[1].first = deviceTemperatures.startracker.isValid(); sensors[1].second = deviceTemperatures.startracker.value; sensors[2].first = sensorTemperatures.dro.isValid(); sensors[2].second = sensorTemperatures.dro.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_5_STR, heater::HEATER_6_DRO, strLimits); ctrlComponentTemperature(htrCtx); tooHotHandlerWhichClearsOneShotFlag(objects::STAR_TRACKER, tooHotFlags.strTooHotFlag); } void ThermalController::ctrlIfBoard() { ctrlCtx.thermalComponent = tcsCtrl::IF_BOARD; sensors[0].first = sensorTemperatures.tmp1075IfBrd.isValid(); sensors[0].second = sensorTemperatures.tmp1075IfBrd.value; sensors[1].first = sensorTemperatures.mgt.isValid(); sensors[1].second = sensorTemperatures.mgt.value; sensors[2].first = deviceTemperatures.mgm2SideB.isValid(); sensors[2].second = deviceTemperatures.mgm2SideB.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_2_ACS_BRD, heater::HEATER_1_PCDU_PDU, ifBoardLimits); ctrlComponentTemperature(htrCtx); // TODO: special event overheating + could go back to safe mode } void ThermalController::ctrlTcsBoard() { ctrlCtx.thermalComponent = tcsCtrl::TCS_BOARD; sensors[0].first = sensorTemperatures.tcsBoard.isValid(); sensors[0].second = sensorTemperatures.tcsBoard.value; sensors[1].first = sensorTemperatures.tmp1075Tcs0.isValid(); sensors[1].second = sensorTemperatures.tmp1075Tcs0.value; sensors[2].first = sensorTemperatures.tmp1075Tcs1.isValid(); sensors[2].second = sensorTemperatures.tmp1075Tcs1.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_3_OBC_BRD, heater::HEATER_2_ACS_BRD, tcsBoardLimits); ctrlComponentTemperature(htrCtx); // TODO: special event overheating + could go back to safe mode } void ThermalController::ctrlObc() { ctrlCtx.thermalComponent = tcsCtrl::OBC; sensors[0].first = deviceTemperatures.q7s.isValid(); sensors[0].second = deviceTemperatures.q7s.value; sensors[1].first = sensorTemperatures.tmp1075Tcs1.isValid(); sensors[1].second = sensorTemperatures.tmp1075Tcs1.value; sensors[2].first = sensorTemperatures.tmp1075Tcs0.isValid(); sensors[2].second = sensorTemperatures.tmp1075Tcs0.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_3_OBC_BRD, heater::HEATER_2_ACS_BRD, obcLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.obcTooHotFlag) { triggerEvent(tcsCtrl::OBC_OVERHEATING, tempFloatToU32()); tooHotFlags.obcTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.obcTooHotFlag = false; } } void ThermalController::ctrlSBandTransceiver() { ctrlCtx.thermalComponent = tcsCtrl::SBAND_TRANSCEIVER; sensors[0].first = deviceTemperatures.syrlinksPowerAmplifier.isValid(); sensors[0].second = deviceTemperatures.syrlinksPowerAmplifier.value; sensors[1].first = deviceTemperatures.syrlinksBasebandBoard.isValid(); sensors[1].second = deviceTemperatures.syrlinksBasebandBoard.value; sensors[2].first = sensorTemperatures.payload4kCamera.isValid(); sensors[2].second = sensorTemperatures.payload4kCamera.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_7_S_BAND, heater::HEATER_4_CAMERA, sBandTransceiverLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.syrlinksTooHotFlag) { triggerEvent(tcsCtrl::SYRLINKS_OVERHEATING, tempFloatToU32()); tooHotFlags.syrlinksTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.syrlinksTooHotFlag = false; } } void ThermalController::ctrlPcduP60Board() { ctrlCtx.thermalComponent = tcsCtrl::PCDUP60_BOARD; sensors[0].first = deviceTemperatures.temp1P60dock.isValid(); sensors[0].second = deviceTemperatures.temp1P60dock.value; sensors[1].first = deviceTemperatures.temp2P60dock.isValid(); sensors[1].second = deviceTemperatures.temp2P60dock.value; numSensors = 2; HeaterContext htrCtx(heater::HEATER_1_PCDU_PDU, heater::HEATER_2_ACS_BRD, pcduP60BoardLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.pcduSystemTooHotFlag) { triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32()); tooHotFlags.pcduSystemTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.pcduSystemTooHotFlag = false; } // TODO: ! } void ThermalController::ctrlPcduAcu() { ctrlCtx.thermalComponent = tcsCtrl::PCDUACU; heater::Switch switchNr = heater::HEATER_1_PCDU_PDU; heater::Switch redSwitchNr = heater::HEATER_2_ACS_BRD; if (chooseHeater(switchNr, redSwitchNr)) { bool sensorTempAvailable = true; // TODO: check if (deviceTemperatures.acu.value[0] != INVALID_TEMPERATURE) { ctrlCtx.sensorTemp = deviceTemperatures.acu.value[0]; } else if (deviceTemperatures.acu.value[1] != INVALID_TEMPERATURE) { ctrlCtx.sensorTemp = deviceTemperatures.acu.value[1]; } else if (deviceTemperatures.acu.value[2] != INVALID_TEMPERATURE) { ctrlCtx.sensorTemp = deviceTemperatures.acu.value[2]; } else if (sensorTemperatures.acu.isValid()) { ctrlCtx.sensorTemp = sensorTemperatures.acu.value; } else { triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, ctrlCtx.thermalComponent); sensorTempAvailable = false; } if (sensorTempAvailable) { HeaterContext htrCtx(switchNr, redSwitchNr, pcduAcuLimits); checkLimitsAndCtrlHeater(htrCtx); } } if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.pcduSystemTooHotFlag) { triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32()); tooHotFlags.pcduSystemTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.pcduSystemTooHotFlag = false; } } void ThermalController::ctrlPcduPdu() { ctrlCtx.thermalComponent = tcsCtrl::PCDUPDU; sensors[0].first = deviceTemperatures.pdu1.isValid(); sensors[0].second = deviceTemperatures.pdu1.value; sensors[1].first = deviceTemperatures.pdu2.isValid(); sensors[1].second = deviceTemperatures.pdu2.value; sensors[2].first = sensorTemperatures.tmp1075Tcs0.isValid(); sensors[2].second = sensorTemperatures.tmp1075Tcs0.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_1_PCDU_PDU, heater::HEATER_2_ACS_BRD, pcduPduLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.pcduSystemTooHotFlag) { triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32()); tooHotFlags.pcduSystemTooHotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.pcduSystemTooHotFlag = false; } } void ThermalController::ctrlPlPcduBoard() { ctrlCtx.thermalComponent = tcsCtrl::PLPCDU_BOARD; sensors[0].first = sensorTemperatures.tmp1075PlPcdu0.isValid(); sensors[0].second = sensorTemperatures.tmp1075PlPcdu0.value; sensors[1].first = sensorTemperatures.tmp1075PlPcdu1.isValid(); sensors[1].second = sensorTemperatures.tmp1075PlPcdu1.value; sensors[2].first = deviceTemperatures.adcPayloadPcdu.isValid(); sensors[2].second = deviceTemperatures.adcPayloadPcdu.value; sensors[3].first = sensorTemperatures.plpcduHeatspreader.isValid(); sensors[3].second = sensorTemperatures.plpcduHeatspreader.value; numSensors = 4; HeaterContext htrCtx(heater::HEATER_1_PCDU_PDU, heater::HEATER_2_ACS_BRD, plPcduBoardLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } // ToDo: remove one of the following 2 void ThermalController::ctrlPlocMissionBoard() { ctrlCtx.thermalComponent = tcsCtrl::PLOCMISSION_BOARD; sensors[0].first = sensorTemperatures.plocMissionboard.isValid(); sensors[0].second = sensorTemperatures.plocMissionboard.value; sensors[1].first = sensorTemperatures.plocHeatspreader.isValid(); sensors[1].second = sensorTemperatures.plocHeatspreader.value; sensors[2].first = sensorTemperatures.dacHeatspreader.isValid(); sensors[2].second = sensorTemperatures.dacHeatspreader.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_0_PLOC_PROC_BRD, heater::HEATER_3_OBC_BRD, plocMissionBoardLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLOC_SUPERVISOR_HANDLER, tooHotFlags.plocTooHotFlag); } void ThermalController::ctrlPlocProcessingBoard() { ctrlCtx.thermalComponent = tcsCtrl::PLOCPROCESSING_BOARD; sensors[0].first = sensorTemperatures.plocMissionboard.isValid(); sensors[0].second = sensorTemperatures.plocMissionboard.value; sensors[1].first = sensorTemperatures.plocHeatspreader.isValid(); sensors[1].second = sensorTemperatures.plocHeatspreader.value; sensors[2].first = sensorTemperatures.dacHeatspreader.isValid(); sensors[2].second = sensorTemperatures.dacHeatspreader.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_0_PLOC_PROC_BRD, heater::HEATER_3_OBC_BRD, plocProcessingBoardLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLOC_SUPERVISOR_HANDLER, tooHotFlags.plocTooHotFlag); } void ThermalController::ctrlDac() { ctrlCtx.thermalComponent = tcsCtrl::DAC; sensors[0].first = sensorTemperatures.dacHeatspreader.isValid(); sensors[0].second = sensorTemperatures.dacHeatspreader.value; sensors[1].first = sensorTemperatures.plocMissionboard.isValid(); sensors[1].second = sensorTemperatures.plocMissionboard.value; sensors[2].first = sensorTemperatures.plocHeatspreader.isValid(); sensors[2].second = sensorTemperatures.plocHeatspreader.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_0_PLOC_PROC_BRD, heater::HEATER_3_OBC_BRD, dacLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlCameraBody() { ctrlCtx.thermalComponent = tcsCtrl::CAMERA; sensors[0].first = sensorTemperatures.payload4kCamera.isValid(); sensors[0].second = sensorTemperatures.payload4kCamera.value; sensors[1].first = sensorTemperatures.dro.isValid(); sensors[1].second = sensorTemperatures.dro.value; sensors[2].first = sensorTemperatures.mpa.isValid(); sensors[2].second = sensorTemperatures.mpa.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_4_CAMERA, heater::HEATER_6_DRO, cameraLimits); ctrlComponentTemperature(htrCtx); if (ctrlCtx.componentAboveUpperLimit and not tooHotFlags.camTooHotOneShotFlag) { triggerEvent(tcsCtrl::CAMERA_OVERHEATING, tempFloatToU32()); CommandMessage msg; HealthMessage::setHealthMessage(&msg, HealthMessage::HEALTH_SET, HealthState::FAULTY); ReturnValue_t result = commandQueue->sendMessage(camId, &msg); if (result != returnvalue::OK) { sif::error << "ThermalController::ctrlCameraBody(): Sending health message failed" << std::endl; } tooHotFlags.camTooHotOneShotFlag = true; } else if (not ctrlCtx.componentAboveUpperLimit) { tooHotFlags.camTooHotOneShotFlag = false; } } void ThermalController::ctrlDro() { ctrlCtx.thermalComponent = tcsCtrl::DRO; sensors[0].first = sensorTemperatures.dro.isValid(); sensors[0].second = sensorTemperatures.dro.value; sensors[1].first = sensorTemperatures.payload4kCamera.isValid(); sensors[1].second = sensorTemperatures.payload4kCamera.value; sensors[2].first = sensorTemperatures.mpa.isValid(); sensors[2].second = sensorTemperatures.mpa.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_4_CAMERA, droLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlX8() { ctrlCtx.thermalComponent = tcsCtrl::X8; sensors[0].first = sensorTemperatures.x8.isValid(); sensors[0].second = sensorTemperatures.x8.value; sensors[1].first = sensorTemperatures.hpa.isValid(); sensors[1].second = sensorTemperatures.hpa.value; sensors[2].first = sensorTemperatures.eBandTx.isValid(); sensors[2].second = sensorTemperatures.eBandTx.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_4_CAMERA, x8Limits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlTx() { ctrlCtx.thermalComponent = tcsCtrl::TX; sensors[0].first = sensorTemperatures.eBandTx.isValid(); sensors[0].second = sensorTemperatures.eBandTx.value; sensors[1].first = sensorTemperatures.x8.isValid(); sensors[1].second = sensorTemperatures.x8.value; sensors[2].first = sensorTemperatures.mpa.isValid(); sensors[2].second = sensorTemperatures.mpa.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_4_CAMERA, txLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlMpa() { ctrlCtx.thermalComponent = tcsCtrl::MPA; sensors[0].first = sensorTemperatures.mpa.isValid(); sensors[0].second = sensorTemperatures.mpa.value; sensors[1].first = sensorTemperatures.hpa.isValid(); sensors[1].second = sensorTemperatures.hpa.value; sensors[2].first = sensorTemperatures.eBandTx.isValid(); sensors[2].second = sensorTemperatures.eBandTx.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_4_CAMERA, mpaLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlHpa() { ctrlCtx.thermalComponent = tcsCtrl::HPA; sensors[0].first = sensorTemperatures.hpa.isValid(); sensors[0].second = sensorTemperatures.hpa.value; sensors[1].first = sensorTemperatures.x8.isValid(); sensors[1].second = sensorTemperatures.x8.value; sensors[2].first = sensorTemperatures.mpa.isValid(); sensors[2].second = sensorTemperatures.mpa.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_4_CAMERA, hpaLimits); ctrlComponentTemperature(htrCtx); tooHotHandler(objects::PLPCDU_HANDLER, tooHotFlags.eBandTooHotFlag); } void ThermalController::ctrlScexBoard() { ctrlCtx.thermalComponent = tcsCtrl::SCEX_BOARD; sensors[0].first = sensorTemperatures.scex.isValid(); sensors[0].second = sensorTemperatures.scex.value; sensors[1].first = sensorTemperatures.x8.isValid(); sensors[1].second = sensorTemperatures.x8.value; sensors[2].first = sensorTemperatures.hpa.isValid(); sensors[2].second = sensorTemperatures.hpa.value; numSensors = 3; HeaterContext htrCtx(heater::HEATER_6_DRO, heater::HEATER_5_STR, scexBoardLimits); ctrlComponentTemperature(htrCtx); tooHotHandlerWhichClearsOneShotFlag(objects::SCEX, tooHotFlags.scexTooHotFlag); } void ThermalController::performThermalModuleCtrl( const tcsCtrl::HeaterSwitchStates& heaterSwitchStates) { ctrlAcsBoard(); ctrlMgt(); ctrlRw(); ctrlStr(); ctrlIfBoard(); ctrlTcsBoard(); ctrlObc(); ctrlSBandTransceiver(); ctrlPcduP60Board(); ctrlPcduAcu(); ctrlPcduPdu(); // Payload components std::array plocInAllowedRange{}; ctrlPlocMissionBoard(); plocInAllowedRange.at(0) = not ctrlCtx.componentAboveUpperLimit; ctrlPlocProcessingBoard(); plocInAllowedRange.at(1) = not ctrlCtx.componentAboveUpperLimit; if (tooHotFlags.plocTooHotFlag) { bool clearFlag = true; for (const auto& inRange : plocInAllowedRange) { if (not inRange) { clearFlag = false; } } if (clearFlag) { tooHotFlags.plocTooHotFlag = false; } } ctrlCameraBody(); ctrlScexBoard(); // E-Band std::array eBandInAllowedRange{}; ctrlPlPcduBoard(); eBandInAllowedRange.at(0) = not ctrlCtx.componentAboveUpperLimit; ctrlDac(); eBandInAllowedRange.at(1) = not ctrlCtx.componentAboveUpperLimit; ctrlDro(); eBandInAllowedRange.at(2) = not ctrlCtx.componentAboveUpperLimit; ctrlX8(); eBandInAllowedRange.at(3) = not ctrlCtx.componentAboveUpperLimit; ctrlHpa(); eBandInAllowedRange.at(4) = not ctrlCtx.componentAboveUpperLimit; ctrlTx(); eBandInAllowedRange.at(5) = not ctrlCtx.componentAboveUpperLimit; ctrlMpa(); eBandInAllowedRange.at(6) = not ctrlCtx.componentAboveUpperLimit; if (tooHotFlags.eBandTooHotFlag) { bool clearFlag = true; for (const auto& inRange : eBandInAllowedRange) { if (not inRange) { clearFlag = false; } } if (clearFlag) { tooHotFlags.eBandTooHotFlag = false; } } } 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 { // No sensors available, so switch the heater off. We can not perform control tasks if we // are blind.. if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { // Also track the counter to prevent heater handler message spam. The heater handle can only // process 2 messages per cycle. if (heaterCtrlAllowed() and (thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter < 3)) { heaterSwitchHelper(htrCtx.switchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); } } } resetSensorsArray(); } bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) { for (unsigned i = 0; i < numSensors; i++) { if (sensors[i].first and sensors[i].second != INVALID_TEMPERATURE and sensors[i].second > SANITY_LIMIT_LOWER_TEMP and sensors[i].second < SANITY_LIMIT_UPPER_TEMP) { ctrlCtx.sensorTemp = sensors[i].second; ctrlCtx.currentSensorIndex = i; thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter = 0; return true; } } thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter++; if (ctrlCtx.thermalComponent != tcsCtrl::RW and ctrlCtx.thermalComponent != tcsCtrl::ACS_BOARD) { if (thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter <= 3) { triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, ctrlCtx.thermalComponent); } } else { if (thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter <= 8) { triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, ctrlCtx.thermalComponent); } } return false; } bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr) { bool heaterAvailable = true; HasHealthIF::HealthState mainHealth = heaterHandler.getHealth(switchNr); heater::SwitchState mainState = heaterHandler.getSwitchState(switchNr); HasHealthIF::HealthState redHealth = heaterHandler.getHealth(redSwitchNr); if (mainHealth == HasHealthIF::EXTERNAL_CONTROL and mainState == heater::SwitchState::ON) { return false; } if (mainHealth != HasHealthIF::HEALTHY) { if (redHealth == HasHealthIF::HEALTHY) { switchNr = redSwitchNr; ctrlCtx.redSwitchNrInUse = true; } else { heaterAvailable = false; // Special case: Ground might command/do something with the heaters, so prevent spam. if (not(mainHealth == EXTERNAL_CONTROL and redHealth == EXTERNAL_CONTROL)) { triggerEvent(tcsCtrl::NO_HEALTHY_HEATER_AVAILABLE, switchNr, redSwitchNr); } } } else { ctrlCtx.redSwitchNrInUse = false; } return heaterAvailable; } void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) { if (not heaterCtrlAllowed()) { return; } if (htrCtx.switchState == heater::SwitchState::ON) { sif::info << "TCS: Component " << static_cast(ctrlCtx.thermalComponent) << " too warm, above " << whatLimit << ", switching off heater" << std::endl; heaterSwitchHelper(htrCtx.switchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].target = heater::SwitchState::OFF; } if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == heater::SwitchState::ON) { heaterSwitchHelper(htrCtx.redSwitchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); heaterStates[htrCtx.redSwitchNr].switchTransition = true; heaterStates[htrCtx.redSwitchNr].target = heater::SwitchState::OFF; } } void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) { ctrlCtx.componentAboveCutOffLimit = false; ctrlCtx.componentAboveUpperLimit = false; // Stay passive during switch transitions, wait for heater switching to complete. Otherwise, // still check whether components are out of range, which might be important information for the // top level control loop. if (heaterStates[htrCtx.switchNr].switchTransition) { htrCtx.doHeaterHandling = false; heaterCtrlCheckUpperLimits(htrCtx); return; } htrCtx.switchState = static_cast(heaterInfo.heaterSwitchState[htrCtx.switchNr]); // Heater off if (htrCtx.switchState == heater::SwitchState::OFF) { if (ctrlCtx.sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) { sif::info << "TCS: Heater " << static_cast(ctrlCtx.thermalComponent) << " ON" << std::endl; heaterSwitchHelper(htrCtx.switchNr, heater::SwitchState::ON, ctrlCtx.thermalComponent); } else { // Even if heater control is now allowed, we can update the state. thermalStates[ctrlCtx.thermalComponent].heating = false; } heaterCtrlCheckUpperLimits(htrCtx); return; } // Heater on if (htrCtx.switchState == heater::SwitchState::ON) { if (thermalStates[ctrlCtx.thermalComponent].heating) { // We are already in a heating cycle, so need to check whether heating task is complete. if (ctrlCtx.sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET and heaterCtrlAllowed()) { sif::info << "TCS: Heater " << static_cast(ctrlCtx.thermalComponent) << " OFF" << std::endl; heaterSwitchHelper(htrCtx.switchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].target = heater::SwitchState::OFF; } 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 (ctrlCtx.sensorTemp >= htrCtx.tempLimit.cutOffLimit) { ctrlCtx.componentAboveCutOffLimit = true; if (not tooHighHandlerAlreadyCalled) { heaterCtrlTempTooHighHandler(htrCtx, "CutOff-Limit"); } } } } bool ThermalController::heaterCtrlCheckUpperLimits(HeaterContext& htrCtx) { if (ctrlCtx.sensorTemp >= htrCtx.tempLimit.nopUpperLimit) { ctrlCtx.componentAboveUpperLimit = true; if (htrCtx.doHeaterHandling) { heaterCtrlTempTooHighHandler(htrCtx, "NOP-Limit"); } ctrlCtx.overHeatEventToTrigger = ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH; return true; } else if (ctrlCtx.sensorTemp >= htrCtx.tempLimit.opUpperLimit) { ctrlCtx.componentAboveUpperLimit = true; if (htrCtx.doHeaterHandling) { heaterCtrlTempTooHighHandler(htrCtx, "OP-Limit"); } ctrlCtx.overHeatEventToTrigger = ThermalComponentIF::COMPONENT_TEMP_HIGH; return true; } return false; } void ThermalController::resetSensorsArray() { for (auto& validValuePair : sensors) { validValuePair.first = false; validValuePair.second = INVALID_TEMPERATURE; } ctrlCtx.thermalComponent = tcsCtrl::NONE; } void ThermalController::heaterTransitionControl( const tcsCtrl::HeaterSwitchStates& currentHeaterStates) { for (unsigned i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { if (heaterStates[i].switchTransition) { if (currentHeaterStates[i] == heaterStates[i].target) { // Required for max heater period control if (currentHeaterStates[i] == heater::SwitchState::ON) { heaterStates[i].heaterOnMaxBurnTime.setTimeout(MAX_HEATER_ON_DURATIONS_MS[i]); heaterStates[i].heaterOnMaxBurnTime.resetTimer(); heaterStates[i].trackHeaterMaxBurnTime = true; } else { heaterStates[i].trackHeaterMaxBurnTime = false; // The heater might still be one for some thermal components, so cross-check // those components crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast(i)); } heaterStates[i].switchTransition = false; heaterStates[i].heaterSwitchControlCycles = 0; continue; } if (heaterStates[i].heaterSwitchControlCycles > 5) { heaterStates[i].switchTransition = false; heaterStates[i].heaterSwitchControlCycles = 0; } heaterStates[i].heaterSwitchControlCycles++; } } } void ThermalController::heaterMaxDurationControl( const tcsCtrl::HeaterSwitchStates& currentHeaterStates) { for (unsigned i = 0; i < heater::Switch::NUMBER_OF_SWITCHES; i++) { // Right now, we only track the maximum duration for heater which were commanded by the TCS // controller. if (heaterHandler.getHealth(static_cast(i)) != HasHealthIF::EXTERNAL_CONTROL and currentHeaterStates[i] == heater::SwitchState::ON and heaterStates[i].trackHeaterMaxBurnTime and heaterStates[i].heaterOnMaxBurnTime.hasTimedOut()) { heaterStates[i].switchTransition = false; heaterStates[i].heaterSwitchControlCycles = 0; heaterStates[i].trackHeaterMaxBurnTime = false; triggerEvent(tcsCtrl::TCS_HEATER_MAX_BURN_TIME_REACHED, static_cast(i), MAX_HEATER_ON_DURATIONS_MS[i]); heaterSwitchHelper(static_cast(i), heater::SwitchState::OFF, std::nullopt); // The heater might still be one for some thermal components, so cross-check // those components crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast(i)); } } } uint32_t ThermalController::tempFloatToU32() const { auto sensorTempAsFloat = static_cast(ctrlCtx.sensorTemp); uint32_t tempRaw = 0; size_t dummyLen = 0; SerializeAdapter::serialize(&sensorTempAsFloat, reinterpret_cast(&tempRaw), &dummyLen, sizeof(tempRaw), SerializeIF::Endianness::NETWORK); return tempRaw; } void ThermalController::setMode(Mode_t mode, Submode_t submode) { if (mode == MODE_OFF) { transitionWhenHeatersOff = false; } this->mode = mode; this->submode = submode; modeHelper.modeChanged(mode, submode); announceMode(false); } bool ThermalController::tooHotHandler(object_id_t object, bool& oneShotFlag) { if (ctrlCtx.componentAboveUpperLimit and not oneShotFlag) { // Too hot -> returns true EventManagerIF::triggerEvent(object, ctrlCtx.overHeatEventToTrigger, tempFloatToU32()); oneShotFlag = true; return true; } return false; } bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO_HEATER_CTRL; } void ThermalController::resetThermalStates() { for (auto& thermalState : thermalStates) { thermalState.heating = false; thermalState.noSensorAvailableCounter = 0; thermalState.heaterStartTime = 0; thermalState.heaterEndTime = 0; thermalState.sensorIndex = 0; thermalState.heaterSwitch = heater::Switch::NUMBER_OF_SWITCHES; } } void ThermalController::heaterSwitchHelper(heater::Switch switchNr, heater::SwitchState targetState, std::optional componentIdx) { timeval currentTime; Clock::getClock(¤tTime); if (targetState == heater::SwitchState::ON) { heaterHandler.switchHeater(switchNr, targetState); heaterStates[switchNr].target = heater::SwitchState::ON; heaterStates[switchNr].switchTransition = true; if (componentIdx.has_value()) { unsigned componentIdxVal = componentIdx.value(); thermalStates[componentIdxVal].sensorIndex = ctrlCtx.currentSensorIndex; thermalStates[componentIdxVal].heaterSwitch = switchNr; thermalStates[componentIdxVal].heating = true; thermalStates[componentIdxVal].heaterStartTime = currentTime.tv_sec; } triggerEvent(tcsCtrl::TCS_SWITCHING_HEATER_ON, static_cast(ctrlCtx.thermalComponent), static_cast(switchNr)); } else { heaterHandler.switchHeater(switchNr, targetState); if (componentIdx.has_value()) { thermalStates[componentIdx.value()].heating = false; thermalStates[componentIdx.value()].heaterEndTime = currentTime.tv_sec; } triggerEvent(tcsCtrl::TCS_SWITCHING_HEATER_OFF, static_cast(ctrlCtx.thermalComponent), static_cast(switchNr)); } } void ThermalController::heaterSwitchHelperAllOff() { timeval currentTime; Clock::getClock(¤tTime); size_t idx = 0; for (; idx < heater::Switch::NUMBER_OF_SWITCHES; idx++) { heaterHandler.switchHeater(static_cast(idx), heater::SwitchState::OFF); } for (idx = 0; idx < thermalStates.size(); idx++) { thermalStates[idx].heating = false; thermalStates[idx].heaterEndTime = currentTime.tv_sec; } } ThermalController::~ThermalController() { if (tmp1075SetPlPcdu1 != nullptr) { delete tmp1075SetPlPcdu1; } } 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::getClock(¤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 ctrlCtx.componentAboveUpperLimit) { oneShotFlag = false; } } void ThermalController::startTransition(Mode_t mode_, Submode_t submode_) { triggerEvent(CHANGING_MODE, mode_, 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))) { heaterSwitchHelperAllOff(); transitionWhenHeatersOff = true; targetMode = mode_; targetSubmode = submode_; transitionWhenHeatersOffCycles = 0; } else { setMode(mode_, submode_); } }