diff --git a/CHANGELOG.md b/CHANGELOG.md index 251ed51e..44c98cb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ will consitute of a breaking change warranting a new major release: ## Changed +- TCS: Remove OBC IF board thermal module, which is exactly identical to OBC module and therefore + obsolete. - Swapped PL and PS I2C, BPX battery and MGT are connected to PS I2C now for firmware versions equal or above v4. However, this software version is compatible to both v3 and v4 of the firmware. - The firmware version variables are global statics inititalized early during the program @@ -26,6 +28,7 @@ will consitute of a breaking change warranting a new major release: components (no sensors available), irrespective of current switch state. - Make OBSW compatible to prospective FW version v5.0.0, where the Q7 I2C devices were moved to a PL I2C block and the TMP sensor devices were moved to the PS I2C0. +- Made `Xadc` code a little bit more robust against errors. ## Fixed @@ -42,6 +45,8 @@ will consitute of a breaking change warranting a new major release: - TMP1075: Possibly ignored health commands. - Bugfix in FSFW where certain packet types could only be sent with source data fields with a maximum size of 255 bytes. +- TCS CTRL: Limit number of heater handler messages sent in case there are not sensors available + anymore. # Added diff --git a/bsp_q7s/xadc/Xadc.cpp b/bsp_q7s/xadc/Xadc.cpp index 34a4e159..43fc7b75 100644 --- a/bsp_q7s/xadc/Xadc.cpp +++ b/bsp_q7s/xadc/Xadc.cpp @@ -129,7 +129,7 @@ ReturnValue_t Xadc::readValFromFile(const char* filename, T& val) { sif::warning << "Xadc::readValFromFile: Failed to open file " << filename << std::endl; return returnvalue::FAILED; } - char valstring[MAX_STR_LENGTH] = ""; + char valstring[MAX_STR_LENGTH]{}; char* returnVal = fgets(valstring, MAX_STR_LENGTH, fp); if (returnVal == nullptr) { sif::warning << "Xadc::readValFromFile: Failed to read string from file " << filename @@ -139,6 +139,11 @@ ReturnValue_t Xadc::readValFromFile(const char* filename, T& val) { } std::istringstream valSstream(valstring); valSstream >> val; + if(valSstream.bad()) { + sif::warning << "Xadc: Conversion of value to target type failed" << std::endl; + fclose(fp); + return returnvalue::FAILED; + } fclose(fp); return returnvalue::OK; } diff --git a/mission/controller/ThermalController.cpp b/mission/controller/ThermalController.cpp index 2c5e2c9e..b87540ec 100644 --- a/mission/controller/ThermalController.cpp +++ b/mission/controller/ThermalController.cpp @@ -1269,25 +1269,6 @@ void ThermalController::ctrlObc() { } } -void ThermalController::ctrlObcIfBoard() { - ctrlCtx.thermalComponent = tcsCtrl::OBCIF_BOARD; - sensors[0].first = deviceTemperatures.q7s.isValid(); - sensors[0].second = deviceTemperatures.q7s.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, obcIfBoardLimits); - 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(); @@ -1554,7 +1535,6 @@ void ThermalController::performThermalModuleCtrl( ctrlIfBoard(); ctrlTcsBoard(); ctrlObc(); - ctrlObcIfBoard(); ctrlSBandTransceiver(); ctrlPcduP60Board(); ctrlPcduAcu(); @@ -1621,9 +1601,11 @@ void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { // No sensors available, so switch the heater off. We can not perform control tasks if we // are blind.. if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { - if (heaterCtrlAllowed()) { - heaterSwitchHelper(htrCtx.switchNr, heater::SwitchState::OFF, ctrlCtx.thermalComponent); - } + // 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, heater::SwitchState::OFF, currThermalComponent); + } } } resetSensorsArray(); @@ -1635,18 +1617,18 @@ bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) { sensors[i].second < SANITY_LIMIT_UPPER_TEMP) { ctrlCtx.sensorTemp = sensors[i].second; ctrlCtx.currentSensorIndex = i; - thermalStates[ctrlCtx.thermalComponent].errorCounter = 0; + thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter = 0; return true; } } - thermalStates[ctrlCtx.thermalComponent].errorCounter++; - if (ctrlCtx.thermalComponent != tcsCtrl::RW and ctrlCtx.thermalComponent != tcsCtrl::ACS_BOARD) { - if (thermalStates[ctrlCtx.thermalComponent].errorCounter <= 3) { + thermalStates[currThermalComponent].noSensorAvailableCounter++; + if (currThermalComponent != RW and currThermalComponent != ACS_BOARD) { + if (thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter <= 3) { triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, ctrlCtx.thermalComponent); } } else { - if (thermalStates[ctrlCtx.thermalComponent].errorCounter <= 8) { + if (thermalStates[ctrlCtx.thermalComponent].noSensorAvailableCounter <= 8) { triggerEvent(tcsCtrl::NO_VALID_SENSOR_TEMPERATURE, ctrlCtx.thermalComponent); } } @@ -1858,7 +1840,7 @@ bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO void ThermalController::resetThermalStates() { for (auto& thermalState : thermalStates) { thermalState.heating = false; - thermalState.errorCounter = 0; + thermalState.noSensorAvailableCounter = 0; thermalState.heaterStartTime = 0; thermalState.heaterEndTime = 0; thermalState.sensorIndex = 0; diff --git a/mission/controller/ThermalController.h b/mission/controller/ThermalController.h index bd3aa1f3..508b49cd 100644 --- a/mission/controller/ThermalController.h +++ b/mission/controller/ThermalController.h @@ -26,6 +26,80 @@ #include #include +/** + * NOP Limit: Hard limit for device, usually from datasheet. Device damage is possible lif NOP limit + * is exceeded. + * OP Limit: Soft limit. Device should be switched off or TCS controller should take action if the + * limit is exceeded to avoid reaching NOP limit + */ +struct TempLimits { + TempLimits(float nopLowerLimit, float opLowerLimit, float cutOffLimit, float opUpperLimit, + float nopUpperLimit) + : opLowerLimit(opLowerLimit), + opUpperLimit(opUpperLimit), + cutOffLimit(cutOffLimit), + nopLowerLimit(nopLowerLimit), + nopUpperLimit(nopUpperLimit) {} + float opLowerLimit; + float opUpperLimit; + float cutOffLimit; + float nopLowerLimit; + float nopUpperLimit; +}; + +struct ThermalState { + uint8_t noSensorAvailableCounter; + // Which sensor is used for this component? + uint8_t sensorIndex = 0; + // Is heating on for that thermal module? + bool heating = false; + // Which switch is being used for heating the component + heater::Switch heaterSwitch = heater::Switch::NUMBER_OF_SWITCHES; + // Heater start time and end times as UNIX seconds. Please note that these times will be updated + // when a switch command is sent, with no guarantess that the heater actually went on. + uint32_t heaterStartTime = 0; + uint32_t heaterEndTime = 0; +}; + +struct HeaterState { + bool switchTransition = false; + HeaterHandler::SwitchState target = HeaterHandler::SwitchState::OFF; + uint8_t heaterSwitchControlCycles = 0; + bool trackHeaterMaxPeriod = false; + Countdown heaterOnPeriod; +}; + +using HeaterSwitchStates = std::array; + +enum ThermalComponents : uint8_t { + NONE = 0, + ACS_BOARD = 1, + MGT = 2, + RW = 3, + STR = 4, + IF_BOARD = 5, + TCS_BOARD = 6, + OBC = 7, + // Not used anymore, was identical to OBC module. + LEGACY_OBCIF_BOARD = 8, + SBAND_TRANSCEIVER = 9, + PCDUP60_BOARD = 10, + PCDUACU = 11, + PCDUPDU = 12, + PLPCDU_BOARD = 13, + PLOCMISSION_BOARD = 14, + PLOCPROCESSING_BOARD = 15, + DAC = 16, + CAMERA = 17, + DRO = 18, + X8 = 19, + HPA = 20, + TX = 21, + MPA = 22, + SCEX_BOARD = 23, + NUM_ENTRIES +}; + class ThermalController : public ExtendedControllerBase { public: static constexpr uint8_t SUBMODE_NO_HEATER_CTRL = 1; @@ -298,7 +372,6 @@ class ThermalController : public ExtendedControllerBase { void ctrlIfBoard(); void ctrlTcsBoard(); void ctrlObc(); - void ctrlObcIfBoard(); void ctrlSBandTransceiver(); void ctrlPcduP60Board(); void ctrlPcduAcu();