#ifndef MISSION_CONTROLLER_THERMALCONTROLLER_H_ #define MISSION_CONTROLLER_THERMALCONTROLLER_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class ThermalController : public ExtendedControllerBase { public: static constexpr uint8_t SUBMODE_NO_HEATER_CTRL = 1; static const uint16_t INVALID_TEMPERATURE = 999; static const uint8_t NUMBER_OF_SENSORS = 16; static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160; // 1 hour static constexpr uint32_t DEFAULT_MAX_HEATER_ON_DURATION_MS = 60 * 60 * 1000; static constexpr uint32_t MAX_HEATER_ON_DURATIONS_MS[8] = {// PLOC PROC board DEFAULT_MAX_HEATER_ON_DURATION_MS, // PCDU PDU DEFAULT_MAX_HEATER_ON_DURATION_MS, // ACS Board DEFAULT_MAX_HEATER_ON_DURATION_MS, // OBC Board DEFAULT_MAX_HEATER_ON_DURATION_MS, // Camera DEFAULT_MAX_HEATER_ON_DURATION_MS, // STR DEFAULT_MAX_HEATER_ON_DURATION_MS, // DRO DEFAULT_MAX_HEATER_ON_DURATION_MS, // S-Band DEFAULT_MAX_HEATER_ON_DURATION_MS}; ThermalController(object_id_t objectId, HeaterHandler& heater, const std::atomic_bool& tcsBoardShortUnavailable, bool pollPcdu1Tmp); virtual ~ThermalController(); ReturnValue_t initialize() override; protected: struct HeaterContext { public: HeaterContext(heater::Switch switchNr, heater::Switch redundantSwitchNr, const tcsCtrl::TempLimits& tempLimit) : switchNr(switchNr), redSwitchNr(redundantSwitchNr), tempLimit(tempLimit) {} bool doHeaterHandling = true; heater::Switch switchNr; heater::SwitchState switchState = heater::SwitchState::OFF; heater::Switch redSwitchNr; const tcsCtrl::TempLimits& tempLimit; }; void performThermalModuleCtrl(const tcsCtrl::HeaterSwitchStates& heaterSwitchStates); ReturnValue_t handleCommandMessage(CommandMessage* message) override; void performControlOperation() override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; // Mode abstract functions ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode) override; private: static const uint32_t INIT_DELAY = 1500; static const uint32_t TEMP_OFFSET = 5; enum class InternalState { STARTUP, INITIAL_DELAY, READY }; InternalState internalState = InternalState::STARTUP; HeaterHandler& heaterHandler; bool pollPcdu1Tmp; tcsCtrl::SensorTemperatures sensorTemperatures; tcsCtrl::SusTemperatures susTemperatures; tcsCtrl::DeviceTemperatures deviceTemperatures; tcsCtrl::HeaterInfo heaterInfo; tcsCtrl::TcsCtrlInfo tcsCtrlInfo; DeviceHandlerThermalSet imtqThermalSet; // Temperature Sensors MAX31865::PrimarySet maxSet0PlocHspd; MAX31865::PrimarySet maxSet1PlocMissionBrd; MAX31865::PrimarySet maxSet2PlCam; MAX31865::PrimarySet maxSet3DacHspd; MAX31865::PrimarySet maxSet4Str; MAX31865::PrimarySet maxSet5Rw1MxMy; MAX31865::PrimarySet maxSet6Dro; MAX31865::PrimarySet maxSet7Scex; MAX31865::PrimarySet maxSet8X8; MAX31865::PrimarySet maxSet9Hpa; MAX31865::PrimarySet maxSet10EbandTx; MAX31865::PrimarySet maxSet11Mpa; MAX31865::PrimarySet maxSet31865Set12; MAX31865::PrimarySet maxSet13PlPcduHspd; MAX31865::PrimarySet maxSet14TcsBrd; MAX31865::PrimarySet maxSet15Imtq; TMP1075::Tmp1075Dataset tmp1075SetTcs0; TMP1075::Tmp1075Dataset tmp1075SetTcs1; TMP1075::Tmp1075Dataset tmp1075SetPlPcdu0; // damaged TMP1075::Tmp1075Dataset* tmp1075SetPlPcdu1; TMP1075::Tmp1075Dataset tmp1075SetIfBoard; // SUS susMax1227::SusDataset susSet0; susMax1227::SusDataset susSet1; susMax1227::SusDataset susSet2; susMax1227::SusDataset susSet3; susMax1227::SusDataset susSet4; susMax1227::SusDataset susSet5; susMax1227::SusDataset susSet6; susMax1227::SusDataset susSet7; susMax1227::SusDataset susSet8; susMax1227::SusDataset susSet9; susMax1227::SusDataset susSet10; susMax1227::SusDataset susSet11; // If the TCS board in unavailable, for example due to a recovery, skip // some TCS controller tasks to avoid unnecessary events. const std::atomic_bool& tcsBrdShortlyUnavailable = false; lp_var_t tempQ7s = lp_var_t(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE); lp_var_t battTemp1 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1); lp_var_t battTemp2 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2); lp_var_t battTemp3 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_3); lp_var_t battTemp4 = lp_var_t(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_4); lp_var_t tempRw1 = lp_var_t(objects::RW1, rws::TEMPERATURE_C); lp_var_t tempRw2 = lp_var_t(objects::RW2, rws::TEMPERATURE_C); lp_var_t tempRw3 = lp_var_t(objects::RW3, rws::TEMPERATURE_C); lp_var_t tempRw4 = lp_var_t(objects::RW4, rws::TEMPERATURE_C); lp_var_t tempStartracker = lp_var_t(objects::STAR_TRACKER, startracker::MCU_TEMPERATURE); lp_var_t tempSyrlinksPowerAmplifier = lp_var_t(objects::SYRLINKS_HANDLER, syrlinks::TEMP_POWER_AMPLIFIER); lp_var_t tempSyrlinksBasebandBoard = lp_var_t(objects::SYRLINKS_HANDLER, syrlinks::TEMP_BASEBAND_BOARD); lp_var_t tempMgt = lp_var_t(objects::IMTQ_HANDLER, imtq::MCU_TEMPERATURE); lp_vec_t tempAcu = lp_vec_t(objects::ACU_HANDLER, ACU::pool::ACU_TEMPERATURES); lp_var_t tempPdu1 = lp_var_t(objects::PDU1_HANDLER, PDU::pool::PDU_TEMPERATURE); lp_var_t tempPdu2 = lp_var_t(objects::PDU2_HANDLER, PDU::pool::PDU_TEMPERATURE); lp_var_t temp1P60dock = lp_var_t(objects::P60DOCK_HANDLER, P60Dock::pool::P60DOCK_TEMPERATURE_1); lp_var_t temp2P60dock = lp_var_t(objects::P60DOCK_HANDLER, P60Dock::pool::P60DOCK_TEMPERATURE_2); lp_var_t tempGyro0 = lp_var_t(objects::GYRO_0_ADIS_HANDLER, adis1650x::TEMPERATURE); lp_var_t tempGyro1 = lp_var_t(objects::GYRO_1_L3G_HANDLER, l3gd20h::TEMPERATURE); lp_var_t tempGyro2 = lp_var_t(objects::GYRO_2_ADIS_HANDLER, adis1650x::TEMPERATURE); lp_var_t tempGyro3 = lp_var_t(objects::GYRO_3_L3G_HANDLER, l3gd20h::TEMPERATURE); lp_var_t tempMgm0 = lp_var_t(objects::MGM_0_LIS3_HANDLER, mgmLis3::TEMPERATURE_CELCIUS); lp_var_t tempMgm2 = lp_var_t(objects::MGM_2_LIS3_HANDLER, mgmLis3::TEMPERATURE_CELCIUS); lp_var_t tempAdcPayloadPcdu = lp_var_t(objects::PLPCDU_HANDLER, plpcdu::TEMP); lp_vec_t currentVecPdu2 = lp_vec_t(gp_id_t(objects::PDU2_HANDLER, PDU::pool::PDU_CURRENTS)); // TempLimits tcsCtrl::TempLimits acsBoardLimits = tcsCtrl::TempLimits(-40.0, -40.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits mgtLimits = tcsCtrl::TempLimits(-40.0, -40.0, 65.0, 70.0, 70.0); tcsCtrl::TempLimits rwLimits = tcsCtrl::TempLimits(-40.0, -40.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits strLimits = tcsCtrl::TempLimits(-30.0, -20.0, 65.0, 70.0, 80.0); tcsCtrl::TempLimits ifBoardLimits = tcsCtrl::TempLimits(-65.0, -40.0, 80.0, 85.0, 150.0); tcsCtrl::TempLimits tcsBoardLimits = tcsCtrl::TempLimits(-60.0, -40.0, 80.0, 85.0, 130.0); tcsCtrl::TempLimits obcLimits = tcsCtrl::TempLimits(-40.0, -40.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits obcIfBoardLimits = tcsCtrl::TempLimits(-65.0, -40.0, 80.0, 85.0, 125.0); tcsCtrl::TempLimits sBandTransceiverLimits = tcsCtrl::TempLimits(-40.0, -25.0, 35.0, 40.0, 65.0); tcsCtrl::TempLimits pcduP60BoardLimits = tcsCtrl::TempLimits(-35.0, -35.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits pcduAcuLimits = tcsCtrl::TempLimits(-35.0, -35.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits pcduPduLimits = tcsCtrl::TempLimits(-35.0, -35.0, 80.0, 85.0, 85.0); tcsCtrl::TempLimits plPcduBoardLimits = tcsCtrl::TempLimits(-55.0, -40.0, 80.0, 85.0, 125.0); tcsCtrl::TempLimits plocMissionBoardLimits = tcsCtrl::TempLimits(-30.0, -5.0, 40.0, 45.0, 60); tcsCtrl::TempLimits plocProcessingBoardLimits = tcsCtrl::TempLimits(-30.0, -5.0, 40.0, 45.0, 60.0); tcsCtrl::TempLimits dacLimits = tcsCtrl::TempLimits(-65.0, -40.0, 113.0, 118.0, 150.0); tcsCtrl::TempLimits cameraLimits = tcsCtrl::TempLimits(-40.0, -30.0, 60.0, 65.0, 85.0); tcsCtrl::TempLimits droLimits = tcsCtrl::TempLimits(-40.0, -30.0, 75.0, 80.0, 90.0); tcsCtrl::TempLimits x8Limits = tcsCtrl::TempLimits(-40.0, -30.0, 75.0, 80.0, 90.0); tcsCtrl::TempLimits hpaLimits = tcsCtrl::TempLimits(-40.0, -30.0, 75.0, 80.0, 90.0); tcsCtrl::TempLimits txLimits = tcsCtrl::TempLimits(-40.0, -30.0, 75.0, 80.0, 90.0); tcsCtrl::TempLimits mpaLimits = tcsCtrl::TempLimits(-40.0, -30.0, 75.0, 80.0, 90.0); tcsCtrl::TempLimits scexBoardLimits = tcsCtrl::TempLimits(-60.0, -40.0, 80.0, 85.0, 150.0); struct CtrlContext { double sensorTemp = INVALID_TEMPERATURE; uint8_t currentSensorIndex = 0; tcsCtrl::ThermalComponents thermalComponent = tcsCtrl::NONE; bool redSwitchNrInUse = false; bool componentAboveCutOffLimit = false; bool componentAboveUpperLimit = false; Event overHeatEventToTrigger; } ctrlCtx; MessageQueueId_t camId = MessageQueueIF::NO_QUEUE; struct TooHotFlags { bool eBandTooHotFlag = false; bool camTooHotOneShotFlag = false; bool scexTooHotFlag = false; bool plocTooHotFlag = false; bool pcduSystemTooHotFlag = false; bool syrlinksTooHotFlag = false; bool obcTooHotFlag = false; bool mgtTooHotFlag = false; bool strTooHotFlag = false; bool rwTooHotFlag = false; } tooHotFlags; bool transitionWhenHeatersOff = false; uint32_t transitionWhenHeatersOffCycles = 0; Mode_t targetMode = MODE_OFF; Submode_t targetSubmode = SUBMODE_NONE; uint32_t cycles = 0; std::array thermalStates{}; std::array heaterStates{}; // Initial delay to make sure all pool variables have been initialized their owners. // Also, wait for system initialization to complete. Countdown initialCountdown = Countdown(INIT_DELAY); #if OBSW_THREAD_TRACING == 1 uint32_t opCounter = 0; #endif std::array, 5> sensors; uint8_t numSensors = 0; PoolEntry tmp1075Tcs0 = PoolEntry({10.0}); PoolEntry tmp1075Tcs1 = PoolEntry({10.0}); PoolEntry tmp1075PlPcdu0 = PoolEntry({10.0}); PoolEntry tmp1075PlPcdu1 = PoolEntry({10.0}); PoolEntry tmp1075IfBrd = PoolEntry({10.0}); PoolEntry heaterSwitchStates = PoolEntry(heater::NUMBER_OF_SWITCHES); PoolEntry heaterCurrent = PoolEntry(); PoolEntry tcsCtrlHeaterOn = PoolEntry(tcsCtrl::NUM_THERMAL_COMPONENTS); PoolEntry tcsCtrlSensorIdx = PoolEntry(tcsCtrl::NUM_THERMAL_COMPONENTS); PoolEntry tcsCtrlHeaterIdx = PoolEntry(tcsCtrl::NUM_THERMAL_COMPONENTS); PoolEntry tcsCtrlStartTimes = PoolEntry(tcsCtrl::NUM_THERMAL_COMPONENTS); PoolEntry tcsCtrlEndTimes = PoolEntry(tcsCtrl::NUM_THERMAL_COMPONENTS); static constexpr dur_millis_t MUTEX_TIMEOUT = 50; void startTransition(Mode_t mode, Submode_t submode) override; bool heaterCtrlAllowed() const; void resetThermalStates(); void resetSensorsArray(); void copySensors(); void copySus(); void copyDevices(); void ctrlComponentTemperature(HeaterContext& heaterContext); void checkLimitsAndCtrlHeater(HeaterContext& heaterContext); bool heaterCtrlCheckUpperLimits(HeaterContext& heaterContext); void heaterCtrlTempTooHighHandler(HeaterContext& heaterContext, const char* whatLimit); bool chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr); bool selectAndReadSensorTemp(HeaterContext& htrCtx); void heaterSwitchHelperAllOff(); void heaterSwitchHelper(heater::Switch switchNr, heater::SwitchState state, std::optional componentIdx); void ctrlAcsBoard(); void ctrlMgt(); void ctrlRw(); void ctrlStr(); void ctrlIfBoard(); void ctrlTcsBoard(); void ctrlObc(); void ctrlSBandTransceiver(); void ctrlPcduP60Board(); void ctrlPcduAcu(); void ctrlPcduPdu(); void ctrlPlPcduBoard(); void ctrlPlocMissionBoard(); void ctrlPlocProcessingBoard(); void ctrlDac(); void ctrlCameraBody(); void ctrlDro(); void ctrlX8(); void ctrlHpa(); void ctrlTx(); void ctrlMpa(); void ctrlScexBoard(); /** * The transition of heaters might take some time. As long as a transition is * going on, the TCS controller works in a reduced form. This function takes care * of tracking transition and capturing their completion. * @param currentHeaterStates */ void heaterTransitionControl(const tcsCtrl::HeaterSwitchStates& currentHeaterStates); /** * Control tasks to prevent heaters being on for prolonged periods. Ideally, this * should never happen, but this task prevents bugs from causing heaters to stay on * for a long time, which draws a lot of power. * @param currentHeaterStates */ void heaterMaxDurationControl(const tcsCtrl::HeaterSwitchStates& currentHeaterStates); void crossCheckHeaterStateOfComponentsWhenHeaterGoesOff(heater::Switch switchIdx); void setMode(Mode_t mode, Submode_t submode); uint32_t tempFloatToU32() const; bool tooHotHandler(object_id_t object, bool& oneShotFlag); void tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag); }; #endif /* MISSION_CONTROLLER_THERMALCONTROLLER_H_ */