eive-obsw/mission/controller/ThermalController.cpp
Robin Mueller ed7d75a777
All checks were successful
EIVE/eive-obsw/pipeline/pr-main This commit looks good
thermal controller
2023-07-11 10:44:46 +02:00

1910 lines
78 KiB
C++

#include "ThermalController.h"
#include <bsp_q7s/core/defs.h>
#include <eive/objects.h>
#include <fsfw/datapool/PoolReadGuard.h>
#include <fsfw/thermal/ThermalComponentIF.h>
#include <fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h>
#include <fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h>
#include <mission/acs/gyroAdisHelpers.h>
#include <mission/acs/imtqHelpers.h>
#include <mission/acs/rwHelpers.h>
#include <mission/acs/str/strHelpers.h>
#include <mission/com/syrlinksDefs.h>
#include <mission/payload/payloadPcduDefinitions.h>
#include <mission/power/bpxBattDefs.h>
#include <mission/power/gsDefs.h>
#include <objects/systemObjectList.h>
// 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),
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<HasHealthIF>(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();
}
}
HeaterSwitchStates heaterSwitchStateArray{};
heaterHandler.getAllSwitchStates(heaterSwitchStateArray);
{
PoolReadGuard pg(&heaterInfo);
std::memcpy(heaterInfo.heaterSwitchState.value, heaterSwitchStateArray.data(), 8);
{
PoolReadGuard pg2(&currentVecPdu2);
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] != HeaterHandler::SwitchState::OFF) {
allSwitchersOff = false;
// if heater still ON after 3 cycles, switch OFF again
if (transitionWhenHeatersOffCycles == 3) {
heaterHandler.switchHeater(static_cast<heater::Switch>(idx),
HeaterHandler::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);
}
}
ReturnValue_t ThermalController::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
localDataPoolMap.emplace(tcsCtrl::SENSOR_PLOC_HEATSPREADER, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_PLOC_MISSIONBOARD, new PoolEntry<float>({1.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_4K_CAMERA, new PoolEntry<float>({2.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_DAC_HEATSPREADER, new PoolEntry<float>({3.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_STARTRACKER, new PoolEntry<float>({4.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_RW1, new PoolEntry<float>({5.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_DRO, new PoolEntry<float>({6.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_SCEX, new PoolEntry<float>({7.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_X8, new PoolEntry<float>({8.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_HPA, new PoolEntry<float>({9.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_TX_MODUL, new PoolEntry<float>({10.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_MPA, new PoolEntry<float>({11.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_ACU, new PoolEntry<float>({12.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_PLPCDU_HEATSPREADER, new PoolEntry<float>({13.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_TCS_BOARD, new PoolEntry<float>({14.0}));
localDataPoolMap.emplace(tcsCtrl::SENSOR_MAGNETTORQUER, new PoolEntry<float>({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<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_6_R_LOC_XFYBZM_PT_XF, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_1_N_LOC_XBYFZM_PT_XB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_7_R_LOC_XBYBZM_PT_XB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_2_N_LOC_XFYBZB_PT_YB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_8_R_LOC_XBYBZB_PT_YB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_3_N_LOC_XFYBZF_PT_YF, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_9_R_LOC_XBYBZB_PT_YF, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_4_N_LOC_XMYFZF_PT_ZF, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_10_N_LOC_XMYBZF_PT_ZF, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_5_N_LOC_XFYMZB_PT_ZB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::SUS_11_R_LOC_XBYMZB_PT_ZB, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::COMPONENT_RW, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_Q7S, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_1, new PoolEntry<int16_t>({0}));
localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_2, new PoolEntry<int16_t>({0}));
localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_3, new PoolEntry<int16_t>({0}));
localDataPoolMap.emplace(tcsCtrl::BATTERY_TEMP_4, new PoolEntry<int16_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_RW1, new PoolEntry<int32_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_RW2, new PoolEntry<int32_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_RW3, new PoolEntry<int32_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_RW4, new PoolEntry<int32_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_STAR_TRACKER, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_SYRLINKS_POWER_AMPLIFIER, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_SYRLINKS_BASEBAND_BOARD, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_MGT, new PoolEntry<int16_t>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_ACU, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_PDU1, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_PDU2, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_1_P60DOCK, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_2_P60DOCK, new PoolEntry<float>({0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_0_SIDE_A, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_1_SIDE_A, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_2_SIDE_B, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_GYRO_3_SIDE_B, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_MGM_0_SIDE_A, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_MGM_2_SIDE_B, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::TEMP_ADC_PAYLOAD_PCDU, new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(tcsCtrl::HEATER_SWITCH_LIST, &heaterSwitchStates);
localDataPoolMap.emplace(tcsCtrl::HEATER_CURRENT, &heaterCurrent);
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));
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;
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<float>(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<float>(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<float>(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<float>(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<float>(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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(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<float>(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<float>(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<float>(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<int16_t>(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<float>(INVALID_TEMPERATURE);
deviceTemperatures.acu[1] = static_cast<float>(INVALID_TEMPERATURE);
deviceTemperatures.acu[2] = static_cast<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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<float>(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
currThermalComponent = 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, HeaterHandler::SwitchState::OFF, currThermalComponent);
}
}
}
}
}
resetSensorsArray();
}
void ThermalController::ctrlMgt() {
currThermalComponent = 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 (componentAboveUpperLimit and not mgtTooHotFlag) {
triggerEvent(tcsCtrl::MGT_OVERHEATING, tempFloatToU32());
mgtTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
mgtTooHotFlag = false;
}
}
void ThermalController::ctrlRw() {
Event eventToTrigger = 0;
bool oneIsAboveLimit = false;
std::array<uint32_t, 4> sensorTemps{};
// RW1
currThermalComponent = 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 (componentAboveUpperLimit) {
oneIsAboveLimit = true;
eventToTrigger = overHeatEventToTrigger;
}
}
// RW2
currThermalComponent = 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 (componentAboveUpperLimit) {
oneIsAboveLimit = true;
if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) {
eventToTrigger = overHeatEventToTrigger;
}
}
}
// RW3
currThermalComponent = 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 (componentAboveUpperLimit) {
oneIsAboveLimit = true;
if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) {
eventToTrigger = overHeatEventToTrigger;
}
}
}
// RW4
currThermalComponent = 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 (componentAboveUpperLimit) {
oneIsAboveLimit = true;
if (eventToTrigger != ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH) {
eventToTrigger = overHeatEventToTrigger;
}
}
}
if (oneIsAboveLimit and not 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]);
rwTooHotFlag = true;
} else if (not oneIsAboveLimit) {
rwTooHotFlag = false;
}
}
void ThermalController::ctrlStr() {
currThermalComponent = 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, strTooHotFlag);
}
void ThermalController::ctrlIfBoard() {
currThermalComponent = 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() {
currThermalComponent = 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() {
currThermalComponent = 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 (componentAboveUpperLimit and not obcTooHotFlag) {
triggerEvent(tcsCtrl::OBC_OVERHEATING, tempFloatToU32());
obcTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
obcTooHotFlag = false;
}
}
void ThermalController::ctrlSBandTransceiver() {
currThermalComponent = 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 (componentAboveUpperLimit and not syrlinksTooHotFlag) {
triggerEvent(tcsCtrl::SYRLINKS_OVERHEATING, tempFloatToU32());
syrlinksTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
syrlinksTooHotFlag = false;
}
}
void ThermalController::ctrlPcduP60Board() {
currThermalComponent = 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 (componentAboveUpperLimit and not pcduSystemTooHotFlag) {
triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32());
pcduSystemTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
pcduSystemTooHotFlag = false;
} // TODO: !
}
void ThermalController::ctrlPcduAcu() {
currThermalComponent = 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) {
sensorTemp = deviceTemperatures.acu.value[0];
} else if (deviceTemperatures.acu.value[1] != INVALID_TEMPERATURE) {
sensorTemp = deviceTemperatures.acu.value[1];
} else if (deviceTemperatures.acu.value[2] != INVALID_TEMPERATURE) {
sensorTemp = deviceTemperatures.acu.value[2];
} else if (sensorTemperatures.acu.isValid()) {
sensorTemp = sensorTemperatures.acu.value;
} else {
triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, currThermalComponent);
sensorTempAvailable = false;
}
if (sensorTempAvailable) {
HeaterContext htrCtx(switchNr, redSwitchNr, pcduAcuLimits);
checkLimitsAndCtrlHeater(htrCtx);
}
}
if (componentAboveUpperLimit and not pcduSystemTooHotFlag) {
triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32());
pcduSystemTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
pcduSystemTooHotFlag = false;
}
}
void ThermalController::ctrlPcduPdu() {
currThermalComponent = 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 (componentAboveUpperLimit and not pcduSystemTooHotFlag) {
triggerEvent(tcsCtrl::PCDU_SYSTEM_OVERHEATING, tempFloatToU32());
pcduSystemTooHotFlag = true;
} else if (not componentAboveUpperLimit) {
pcduSystemTooHotFlag = false;
}
}
void ThermalController::ctrlPlPcduBoard() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlPlocMissionBoard() {
currThermalComponent = PLOCMISSION_BOARD;
sensors[0].first = sensorTemperatures.plocHeatspreader.isValid();
sensors[0].second = sensorTemperatures.plocHeatspreader.value;
sensors[1].first = sensorTemperatures.plocMissionboard.isValid();
sensors[1].second = sensorTemperatures.plocMissionboard.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, plocTooHotFlag);
}
void ThermalController::ctrlPlocProcessingBoard() {
currThermalComponent = 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, plocTooHotFlag);
}
void ThermalController::ctrlDac() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlCameraBody() {
currThermalComponent = 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 (componentAboveUpperLimit and not 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;
}
camTooHotOneShotFlag = true;
} else if (not componentAboveUpperLimit) {
camTooHotOneShotFlag = false;
}
}
void ThermalController::ctrlDro() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlX8() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlTx() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlMpa() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlHpa() {
currThermalComponent = 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, eBandTooHotFlag);
}
void ThermalController::ctrlScexBoard() {
currThermalComponent = 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, scexTooHotFlag);
}
void ThermalController::performThermalModuleCtrl(const HeaterSwitchStates& heaterSwitchStates) {
ctrlAcsBoard();
ctrlMgt();
ctrlRw();
ctrlStr();
ctrlIfBoard();
ctrlTcsBoard();
ctrlObc();
ctrlSBandTransceiver();
ctrlPcduP60Board();
ctrlPcduAcu();
ctrlPcduPdu();
// Payload components
std::array<bool, 2> plocInAllowedRange{};
ctrlPlocMissionBoard();
plocInAllowedRange.at(0) = not componentAboveUpperLimit;
ctrlPlocProcessingBoard();
plocInAllowedRange.at(1) = not componentAboveUpperLimit;
if (plocTooHotFlag) {
bool clearFlag = true;
for (const auto& inRange : plocInAllowedRange) {
if (not inRange) {
clearFlag = false;
}
}
if (clearFlag) {
plocTooHotFlag = false;
}
}
ctrlCameraBody();
ctrlScexBoard();
// E-Band
std::array<bool, 7> eBandInAllowedRange{};
ctrlPlPcduBoard();
eBandInAllowedRange.at(0) = not componentAboveUpperLimit;
ctrlDac();
eBandInAllowedRange.at(1) = not componentAboveUpperLimit;
ctrlDro();
eBandInAllowedRange.at(2) = not componentAboveUpperLimit;
ctrlX8();
eBandInAllowedRange.at(3) = not componentAboveUpperLimit;
ctrlHpa();
eBandInAllowedRange.at(4) = not componentAboveUpperLimit;
ctrlTx();
eBandInAllowedRange.at(5) = not componentAboveUpperLimit;
ctrlMpa();
eBandInAllowedRange.at(6) = not componentAboveUpperLimit;
if (eBandTooHotFlag) {
bool clearFlag = true;
for (const auto& inRange : eBandInAllowedRange) {
if (not inRange) {
clearFlag = false;
}
}
if (clearFlag) {
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[currThermalComponent].noSensorAvailableCounter < 3)) {
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, currThermalComponent);
}
}
}
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) {
sensorTemp = sensors[i].second;
currentSensorIndex = i;
thermalStates[currThermalComponent].noSensorAvailableCounter = 0;
return true;
}
}
thermalStates[currThermalComponent].noSensorAvailableCounter++;
if (currThermalComponent != RW and currThermalComponent != ACS_BOARD) {
if (thermalStates[currThermalComponent].noSensorAvailableCounter <= 3) {
triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, currThermalComponent);
}
} else {
if (thermalStates[currThermalComponent].noSensorAvailableCounter <= 8) {
triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, currThermalComponent);
}
}
return false;
}
bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr) {
bool heaterAvailable = true;
HasHealthIF::HealthState mainHealth = heaterHandler.getHealth(switchNr);
HasHealthIF::HealthState redHealth = heaterHandler.getHealth(redSwitchNr);
if (mainHealth != HasHealthIF::HEALTHY) {
if (redHealth == HasHealthIF::HEALTHY) {
switchNr = redSwitchNr;
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 {
redSwitchNrInUse = false;
}
return heaterAvailable;
}
void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) {
if (not heaterCtrlAllowed()) {
return;
}
if (htrCtx.switchState == HeaterHandler::SwitchState::ON) {
sif::info << "TCS: Component " << static_cast<int>(currThermalComponent) << " too warm, above "
<< whatLimit << ", switching off heater" << std::endl;
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, currThermalComponent);
heaterStates[htrCtx.switchNr].switchTransition = true;
heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF;
}
if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == HeaterHandler::SwitchState::ON) {
heaterSwitchHelper(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF, currThermalComponent);
heaterStates[htrCtx.redSwitchNr].switchTransition = true;
heaterStates[htrCtx.redSwitchNr].target = HeaterHandler::SwitchState::OFF;
}
}
void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) {
componentAboveCutOffLimit = false;
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<HeaterHandler::SwitchState>(heaterInfo.heaterSwitchState[htrCtx.switchNr]);
// Heater off
if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) {
if (sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) {
sif::info << "TCS: Heater " << static_cast<int>(htrCtx.switchNr) << " for component "
<< static_cast<int>(currThermalComponent) << " ON" << std::endl;
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::ON, currThermalComponent);
} else {
// Even if heater control is now allowed, we can update the state.
thermalStates[currThermalComponent].heating = false;
}
heaterCtrlCheckUpperLimits(htrCtx);
return;
}
// Heater on
if (htrCtx.switchState == HeaterHandler::SwitchState::ON) {
if (thermalStates[currThermalComponent].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<int>(htrCtx.switchNr) << " for component "
<< static_cast<int>(currThermalComponent) << " OFF" << std::endl;
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, currThermalComponent);
heaterStates[htrCtx.switchNr].switchTransition = true;
heaterStates[htrCtx.switchNr].target = HeaterHandler::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 (sensorTemp >= htrCtx.tempLimit.cutOffLimit) {
componentAboveCutOffLimit = true;
if (not tooHighHandlerAlreadyCalled) {
heaterCtrlTempTooHighHandler(htrCtx, "CutOff-Limit");
}
}
}
}
bool ThermalController::heaterCtrlCheckUpperLimits(HeaterContext& htrCtx) {
if (sensorTemp >= htrCtx.tempLimit.nopUpperLimit) {
componentAboveUpperLimit = true;
if (htrCtx.doHeaterHandling) {
heaterCtrlTempTooHighHandler(htrCtx, "NOP-Limit");
}
overHeatEventToTrigger = ThermalComponentIF::COMPONENT_TEMP_OOL_HIGH;
return true;
} else if (sensorTemp >= htrCtx.tempLimit.opUpperLimit) {
componentAboveUpperLimit = true;
if (htrCtx.doHeaterHandling) {
heaterCtrlTempTooHighHandler(htrCtx, "OP-Limit");
}
overHeatEventToTrigger = ThermalComponentIF::COMPONENT_TEMP_HIGH;
return true;
}
return false;
}
void ThermalController::resetSensorsArray() {
for (auto& validValuePair : sensors) {
validValuePair.first = false;
validValuePair.second = INVALID_TEMPERATURE;
}
currThermalComponent = NONE;
}
void ThermalController::heaterTransitionControl(const 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] == HeaterHandler::SwitchState::ON) {
heaterStates[i].heaterOnPeriod.setTimeout(MAX_HEATER_ON_DURATIONS_MS[i]);
heaterStates[i].heaterOnPeriod.resetTimer();
heaterStates[i].trackHeaterMaxPeriod = true;
} else {
heaterStates[i].trackHeaterMaxPeriod = false;
// The heater might still be one for some thermal components, so cross-check
// those components
crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast<heater::Switch>(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 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 (currentHeaterStates[i] == HeaterHandler::SwitchState::ON and
heaterStates[i].trackHeaterMaxPeriod and heaterStates[i].heaterOnPeriod.hasTimedOut()) {
heaterStates[i].switchTransition = false;
heaterStates[i].heaterSwitchControlCycles = 0;
heaterStates[i].trackHeaterMaxPeriod = false;
triggerEvent(tcsCtrl::TCS_HEATER_MAX_BURN_TIME_REACHED, static_cast<uint32_t>(i),
MAX_HEATER_ON_DURATIONS_MS[i]);
heaterSwitchHelper(static_cast<heater::Switch>(i), HeaterHandler::SwitchState::OFF,
std::nullopt);
// The heater might still be one for some thermal components, so cross-check
// those components
crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(static_cast<heater::Switch>(i));
}
}
}
uint32_t ThermalController::tempFloatToU32() const {
auto sensorTempAsFloat = static_cast<float>(sensorTemp);
uint32_t tempRaw = 0;
size_t dummyLen = 0;
SerializeAdapter::serialize(&sensorTempAsFloat, reinterpret_cast<uint8_t*>(&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 (componentAboveUpperLimit and not oneShotFlag) {
// Too hot -> returns true
EventManagerIF::triggerEvent(object, 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,
HeaterHandler::SwitchState targetState,
std::optional<unsigned> componentIdx) {
timeval currentTime;
Clock::getClockMonotonic(&currentTime);
if (targetState == HeaterHandler::SwitchState::ON) {
heaterHandler.switchHeater(switchNr, targetState);
heaterStates[switchNr].target = HeaterHandler::SwitchState::ON;
heaterStates[switchNr].switchTransition = true;
if (componentIdx.has_value()) {
unsigned componentIdxVal = componentIdx.value();
thermalStates[componentIdxVal].sensorIndex = currentSensorIndex;
thermalStates[componentIdxVal].heaterSwitch = switchNr;
thermalStates[componentIdxVal].heating = true;
thermalStates[componentIdxVal].heaterStartTime = currentTime.tv_sec;
}
triggerEvent(tcsCtrl::TCS_SWITCHING_HEATER_ON, static_cast<uint32_t>(currThermalComponent),
static_cast<uint32_t>(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<uint32_t>(currThermalComponent),
static_cast<uint32_t>(switchNr));
}
}
void ThermalController::heaterSwitchHelperAllOff() {
timeval currentTime;
Clock::getClockMonotonic(&currentTime);
size_t idx = 0;
for (; idx < heater::Switch::NUMBER_OF_SWITCHES; idx++) {
heaterHandler.switchHeater(static_cast<heater::Switch>(idx), HeaterHandler::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::getClockMonotonic(&currentTime);
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) {
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_);
}
}