Merge pull request 'TCS continued' (#576) from continue_tcs_tests into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #576
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
This commit is contained in:
Robin Müller 2023-04-13 18:10:34 +02:00
commit b5f4b6cf7b
17 changed files with 295 additions and 167 deletions

View File

@ -37,6 +37,7 @@ will consitute of a breaking change warranting a new major release:
- Bugfixes and improvements for SDC state machine. Internal state was not updated correctly due - Bugfixes and improvements for SDC state machine. Internal state was not updated correctly due
to a regression, so commanding the SDC state machine externally lead to confusing results. to a regression, so commanding the SDC state machine externally lead to confusing results.
- Heater states array in TCS controller was too small.
- Fixed a bug in persistent TM store, where the active file was not reset of SD card switches. - Fixed a bug in persistent TM store, where the active file was not reset of SD card switches.
SD card switch from 0 to 1 and vice-versa works without errors from persistent TM stores now. SD card switch from 0 to 1 and vice-versa works without errors from persistent TM stores now.
- Add a way for the SUS polling to detect broken or off devices by checking the retrieved - Add a way for the SUS polling to detect broken or off devices by checking the retrieved
@ -52,16 +53,22 @@ will consitute of a breaking change warranting a new major release:
the active SD card is switched or there is a transition from hot redundant to cold redundant mode. the active SD card is switched or there is a transition from hot redundant to cold redundant mode.
This gives other tasks some time to register the SD cards being unusable, and therefore provides This gives other tasks some time to register the SD cards being unusable, and therefore provides
a way for them to perform any re-initialization tasks necessary after SD card switches. a way for them to perform any re-initialization tasks necessary after SD card switches.
- TCS controller now only has an OFF mode and an ON mode
- The TCS controller pauses operations related to the TCS board assembly (reading sensors and - The TCS controller pauses operations related to the TCS board assembly (reading sensors and
the primary control loop) while a TCS board recovery is on-going. the primary control loop) while a TCS board recovery is on-going.
## Changed
- Allow specifying custom OBSW update filename. This allowed keeping a cleaner file structure - Allow specifying custom OBSW update filename. This allowed keeping a cleaner file structure
where each update has a name including the version where each update has a name including the version
- The files extracted during an update process are deleted after the update was performed to keep - The files extracted during an update process are deleted after the update was performed to keep
the update directory cleaner. the update directory cleaner.
## Added
- TCS controller: SUBMODE_NO_HEATER_CTRL (1) added for ON mode. If this submode is
commanded, all heaters will be switched off and then no further heater
commanding will be done.
- Fixed a bug in persistent TM store, where the active file was not reset of SD card switches.
SD card switch from 0 to 1 and vice-versa works without errors from persistent TM stores now.
# [v1.44.0] 2023-04-07 # [v1.44.0] 2023-04-07
- eive-tmtc: v2.22.0 - eive-tmtc: v2.22.0

View File

@ -94,6 +94,9 @@ set(OBSW_ADD_SUN_SENSORS
set(OBSW_ADD_SUS_BOARD_ASS set(OBSW_ADD_SUS_BOARD_ASS
${INIT_VAL} ${INIT_VAL}
CACHE STRING "Add sun sensor board assembly") CACHE STRING "Add sun sensor board assembly")
set(OBSW_ADD_THERMAL_TEMP_INSERTER
${OBSW_Q7S_EM}
CACHE STRING "Add thermal sensor temperature inserter")
set(OBSW_ADD_ACS_BOARD set(OBSW_ADD_ACS_BOARD
${INIT_VAL} ${INIT_VAL}
CACHE STRING "Add ACS board module") CACHE STRING "Add ACS board module")

View File

@ -151,7 +151,6 @@ void scheduling::initTasks() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
scheduling::printAddObjectError("Core controller dummy", objects::CORE_CONTROLLER); scheduling::printAddObjectError("Core controller dummy", objects::CORE_CONTROLLER);
} }
result = thermalTask->addComponent(objects::THERMAL_CONTROLLER); result = thermalTask->addComponent(objects::THERMAL_CONTROLLER);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER); scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER);

View File

@ -43,6 +43,9 @@
#define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@ #define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@
#define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@ #define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@
#define OBSW_ADD_CCSDS_IP_CORES @OBSW_ADD_CCSDS_IP_CORES@ #define OBSW_ADD_CCSDS_IP_CORES @OBSW_ADD_CCSDS_IP_CORES@
// Only relevant for EM for TCS tests.
#define OBSW_ADD_THERMAL_TEMP_INSERTER @OBSW_ADD_THERMAL_TEMP_INSERTER@
// Set to 1 if all telemetry should be sent to the PTME IP Core // Set to 1 if all telemetry should be sent to the PTME IP Core
#define OBSW_TM_TO_PTME @OBSW_TM_TO_PTME@ #define OBSW_TM_TO_PTME @OBSW_TM_TO_PTME@
// Set to 1 if telecommands are received via the PDEC IP Core // Set to 1 if telecommands are received via the PDEC IP Core

View File

@ -302,6 +302,9 @@ void scheduling::initTasks() {
PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask( PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask(
"TCS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING); "TCS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc, &RR_SCHEDULING);
#if OBSW_ADD_THERMAL_TEMP_INSERTER == 1
tcsSystemTask->addComponent(objects::THERMAL_TEMP_INSERTER);
#endif
scheduling::scheduleRtdSensors(tcsSystemTask); scheduling::scheduleRtdSensors(tcsSystemTask);
result = tcsSystemTask->addComponent(objects::TCS_SUBSYSTEM); result = tcsSystemTask->addComponent(objects::TCS_SUBSYSTEM);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
@ -317,12 +320,10 @@ void scheduling::initTasks() {
scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER); scheduling::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER);
} }
#endif #endif
#if OBSW_ADD_HEATERS == 1
result = tcsSystemTask->addComponent(objects::HEATER_HANDLER); result = tcsSystemTask->addComponent(objects::HEATER_HANDLER);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
scheduling::printAddObjectError("HEATER_HANDLER", objects::HEATER_HANDLER); scheduling::printAddObjectError("HEATER_HANDLER", objects::HEATER_HANDLER);
} }
#endif
#if OBSW_ADD_SYRLINKS == 1 #if OBSW_ADD_SYRLINKS == 1
PeriodicTaskIF* syrlinksCom = factory->createPeriodicTask( PeriodicTaskIF* syrlinksCom = factory->createPeriodicTask(

View File

@ -1,20 +0,0 @@
#ifndef FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_
#define FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_
#include <cstdint>
namespace heater {
enum Switchers : uint8_t {
HEATER_0_OBC_BRD,
HEATER_1_PLOC_PROC_BRD,
HEATER_2_ACS_BRD,
HEATER_3_PCDU_PDU,
HEATER_4_CAMERA,
HEATER_5_STR,
HEATER_6_DRO,
HEATER_7_S_BAND,
NUMBER_OF_SWITCHES
};
}
#endif /* FSFWCONFIG_DEVICES_HEATERSWITCHERLIST_H_ */

View File

@ -1,5 +1,6 @@
#include "TemperatureSensorInserter.h" #include "TemperatureSensorInserter.h"
#include <fsfw/datapool/PoolReadGuard.h>
#include <objects/systemObjectList.h> #include <objects/systemObjectList.h>
#include <cmath> #include <cmath>
@ -14,10 +15,7 @@ TemperatureSensorInserter::TemperatureSensorInserter(object_id_t objectId,
tmp1075DummyMap(std::move(tempTmpSensorDummies_)) {} tmp1075DummyMap(std::move(tempTmpSensorDummies_)) {}
ReturnValue_t TemperatureSensorInserter::initialize() { ReturnValue_t TemperatureSensorInserter::initialize() {
if (performTest) { testCase = TestCase::COLD_STR_CONSECUTIVE;
if (testCase == TestCase::COOL_SYRLINKS) {
}
}
return returnvalue::OK; return returnvalue::OK;
} }
@ -33,35 +31,72 @@ ReturnValue_t TemperatureSensorInserter::performOperation(uint8_t opCode) {
tempsWereInitialized = true; tempsWereInitialized = true;
} }
if (cycles == 10) { switch (testCase) {
max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-100, true); case (TestCase::NONE): {
max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(-100, true); break;
}
case (TestCase::COLD_SYRLINKS): {
// TODO: How do I insert this?
// Does not work on EM, where a real syrlinks device is connected.
if (cycles == 15) {
lp_var_t<float> tempSyrlinksBasebandBoard =
lp_var_t<float>(objects::SYRLINKS_HANDLER, syrlinks::TEMP_BASEBAND_BOARD);
PoolReadGuard pg(&tempSyrlinksBasebandBoard);
tempSyrlinksBasebandBoard.value = -50;
}
if (cycles == 30) {
lp_var_t<float> tempSyrlinksBasebandBoard =
lp_var_t<float>(objects::SYRLINKS_HANDLER, syrlinks::TEMP_BASEBAND_BOARD);
PoolReadGuard pg(&tempSyrlinksBasebandBoard);
tempSyrlinksBasebandBoard.value = 0;
}
break;
}
case (TestCase::COLD_HPA): {
if (cycles == 15) {
sif::debug << "Setting cold HPA temperature" << std::endl;
max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-60, true);
}
if (cycles == 30) {
sif::debug << "Setting HPA temperature back to normal" << std::endl;
max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(0, true);
}
break;
}
case (TestCase::COLD_MGT): {
if (cycles == 15) {
sif::debug << "Setting cold MGT temperature" << std::endl;
max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(-60, true);
}
if (cycles == 30) {
sif::debug << "Setting MGT temperature back to normal" << std::endl;
max31865DummyMap[objects::RTD_15_IC18_IMTQ]->setTemperature(0, true);
}
break;
}
case (TestCase::COLD_STR):
case (TestCase::COLD_STR_CONSECUTIVE): {
if (cycles == 15) {
sif::debug << "Setting cold STR temperature" << std::endl;
max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(-40, true);
}
if (cycles == 30) {
sif::debug << "Setting STR temperature back to normal" << std::endl;
max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(0, true);
}
if (testCase == TestCase::COLD_STR_CONSECUTIVE) {
if (cycles == 45) {
sif::debug << "Setting cold STR temperature again" << std::endl;
max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(-40, true);
}
if (cycles == 60) {
sif::debug << "Setting STR temperature back to normal again" << std::endl;
max31865DummyMap[objects::RTD_4_IC7_STARTRACKER]->setTemperature(0, true);
}
}
break;
}
} }
if (cycles == 35) {
max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(0, true);
max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(0, true);
max31865DummyMap[objects::RTD_2_IC5_4K_CAMERA]->setTemperature(-100, true);
}
if (cycles == 60) {
max31865DummyMap[objects::RTD_9_IC12_HPA]->setTemperature(-100, true);
max31865DummyMap[objects::RTD_11_IC14_MPA]->setTemperature(0, true);
}
/*
ReturnValue_t result = max31865PlocHeatspreaderSet.read();
if (result != returnvalue::OK) {
sif::warning << "Failed to read temperature from MAX31865 dataset" << std::endl;
}
max31865PlocHeatspreaderSet.rtdValue = value - 5;
max31865PlocHeatspreaderSet.temperatureCelcius = value;
if ((iteration % 100) < 20) {
max31865PlocHeatspreaderSet.setValidity(false, true);
} else {
max31865PlocHeatspreaderSet.setValidity(true, true);
}
max31865PlocHeatspreaderSet.commit();
*/
cycles++; cycles++;
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <fsfw/controller/ExtendedControllerBase.h> #include <fsfw/controller/ExtendedControllerBase.h>
#include <mission/com/syrlinksDefs.h>
#include <mission/tcs/Max31865Definitions.h> #include <mission/tcs/Max31865Definitions.h>
#include "Max31865Dummy.h" #include "Max31865Dummy.h"
@ -22,11 +23,18 @@ class TemperatureSensorInserter : public ExecutableObjectIF, public SystemObject
private: private:
Max31865DummyMap max31865DummyMap; Max31865DummyMap max31865DummyMap;
Tmp1075DummyMap tmp1075DummyMap; Tmp1075DummyMap tmp1075DummyMap;
enum TestCase { NONE = 0, COOL_SYRLINKS = 1 };
enum TestCase {
NONE = 0,
COLD_SYRLINKS = 1,
COLD_HPA = 2,
COLD_MGT = 3,
COLD_STR = 4,
COLD_STR_CONSECUTIVE = 5,
};
int iteration = 0; int iteration = 0;
uint32_t cycles = 0; uint32_t cycles = 0;
bool tempsWereInitialized = false; bool tempsWereInitialized = false;
bool performTest = false;
TestCase testCase = TestCase::NONE; TestCase testCase = TestCase::NONE;
// void noise(); // void noise();

View File

@ -194,9 +194,11 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
tmpSensorDummies.emplace( tmpSensorDummies.emplace(
objects::TMP1075_HANDLER_PLPCDU_0, objects::TMP1075_HANDLER_PLPCDU_0,
new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_0, objects::DUMMY_COM_IF, comCookieDummy)); new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_0, objects::DUMMY_COM_IF, comCookieDummy));
tmpSensorDummies.emplace( // damaged.
objects::TMP1075_HANDLER_PLPCDU_1, // tmpSensorDummies.emplace(
new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF, comCookieDummy)); // objects::TMP1075_HANDLER_PLPCDU_1,
// new Tmp1075Dummy(objects::TMP1075_HANDLER_PLPCDU_1, objects::DUMMY_COM_IF,
// comCookieDummy));
tmpSensorDummies.emplace( tmpSensorDummies.emplace(
objects::TMP1075_HANDLER_IF_BOARD, objects::TMP1075_HANDLER_IF_BOARD,
new Tmp1075Dummy(objects::TMP1075_HANDLER_IF_BOARD, objects::DUMMY_COM_IF, comCookieDummy)); new Tmp1075Dummy(objects::TMP1075_HANDLER_IF_BOARD, objects::DUMMY_COM_IF, comCookieDummy));

View File

@ -17,7 +17,7 @@
#include <objects/systemObjectList.h> #include <objects/systemObjectList.h>
// Enabling this should trigger a special event which in turn should trigger a system reaction. // Enabling this should trigger a special event which in turn should trigger a system reaction.
#define LOWER_SYRLINKS_UPPER_LIMITS 0 #define LOWER_SYRLINKS_UPPER_LIMITS 1
#define LOWER_EBAND_UPPER_LIMITS 0 #define LOWER_EBAND_UPPER_LIMITS 0
#define LOWER_PLOC_UPPER_LIMITS 0 #define LOWER_PLOC_UPPER_LIMITS 0
@ -170,26 +170,31 @@ void ThermalController::performControlOperation() {
} }
} }
if (transitionToOff) { cycles++;
for (const auto& switchState : heaterSwitchStateArray) { if (transitionWhenHeatersOff) {
if (switchState != HeaterHandler::SwitchState::OFF) { bool allSwitchersOff = true;
transitionToOffCycles++; for (size_t idx = 0; idx < heaterSwitchStateArray.size(); idx++) {
// if heater still ON after 10 cycles, switch OFF again if (heaterSwitchStateArray[idx] != HeaterHandler::SwitchState::OFF) {
if (transitionToOffCycles == 10) { allSwitchersOff = false;
for (uint8_t i = 0; i < heater::Switchers::NUMBER_OF_SWITCHES; i++) { // if heater still ON after 3 cycles, switch OFF again
heaterHandler.switchHeater(static_cast<heater::Switchers>(i), if (transitionWhenHeatersOffCycles == 3) {
HeaterHandler::SwitchState::OFF); heaterHandler.switchHeater(static_cast<heater::Switch>(idx),
} HeaterHandler::SwitchState::OFF);
triggerEvent(tcsCtrl::HEATER_NOT_OFF_FOR_OFF_MODE); triggerEvent(tcsCtrl::HEATER_NOT_OFF_FOR_OFF_MODE);
} }
return;
} }
setMode(MODE_OFF); }
if (allSwitchersOff or transitionWhenHeatersOffCycles == 6) {
// Finish the transition
transitionWhenHeatersOff = false;
resetThermalStates();
setMode(targetMode, targetSubmode);
} else {
transitionWhenHeatersOffCycles++;
} }
} else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) { } else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) {
performThermalModuleCtrl(heaterSwitchStateArray); performThermalModuleCtrl(heaterSwitchStateArray);
} }
cycles++;
} }
ReturnValue_t ThermalController::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, ReturnValue_t ThermalController::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
@ -292,12 +297,18 @@ LocalPoolDataSetBase* ThermalController::getDataSetHandle(sid_t sid) {
ReturnValue_t ThermalController::checkModeCommand(Mode_t mode, Submode_t submode, ReturnValue_t ThermalController::checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t* msToReachTheMode) { 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) { if (submode != SUBMODE_NONE) {
return INVALID_SUBMODE; return INVALID_SUBMODE;
} }
if ((mode != MODE_OFF) && (mode != MODE_ON) && (mode != MODE_NORMAL)) {
return INVALID_MODE;
}
return returnvalue::OK; return returnvalue::OK;
} }
@ -976,8 +987,8 @@ void ThermalController::copyDevices() {
} }
void ThermalController::ctrlAcsBoard() { void ThermalController::ctrlAcsBoard() {
heater::Switchers switchNr = heater::HEATER_2_ACS_BRD; heater::Switch switchNr = heater::HEATER_2_ACS_BRD;
heater::Switchers redSwitchNr = heater::HEATER_0_OBC_BRD; heater::Switch redSwitchNr = heater::HEATER_0_OBC_BRD;
// A side // A side
thermalComponent = ACS_BOARD; thermalComponent = ACS_BOARD;
@ -1023,7 +1034,9 @@ void ThermalController::ctrlAcsBoard() {
} else { } else {
if (chooseHeater(switchNr, redSwitchNr)) { if (chooseHeater(switchNr, redSwitchNr)) {
if (heaterHandler.getSwitchState(switchNr)) { if (heaterHandler.getSwitchState(switchNr)) {
heaterHandler.switchHeater(switchNr, HeaterHandler::SwitchState::OFF); if (submode != SUBMODE_NO_HEATER_CTRL) {
heaterSwitchHelper(switchNr, HeaterHandler::SwitchState::OFF, thermalComponent);
}
} }
} }
} }
@ -1268,8 +1281,8 @@ void ThermalController::ctrlPcduP60Board() {
void ThermalController::ctrlPcduAcu() { void ThermalController::ctrlPcduAcu() {
thermalComponent = PCDUACU; thermalComponent = PCDUACU;
heater::Switchers switchNr = heater::HEATER_3_PCDU_PDU; heater::Switch switchNr = heater::HEATER_3_PCDU_PDU;
heater::Switchers redSwitchNr = heater::HEATER_2_ACS_BRD; heater::Switch redSwitchNr = heater::HEATER_2_ACS_BRD;
if (chooseHeater(switchNr, redSwitchNr)) { if (chooseHeater(switchNr, redSwitchNr)) {
bool sensorTempAvailable = true; bool sensorTempAvailable = true;
@ -1557,13 +1570,16 @@ void ThermalController::performThermalModuleCtrl(const HeaterSwitchStates& heate
void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) { void ThermalController::ctrlComponentTemperature(HeaterContext& htrCtx) {
if (selectAndReadSensorTemp(htrCtx)) { if (selectAndReadSensorTemp(htrCtx)) {
if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) { if (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) {
// Core loop for a thermal component, after sensors and heaters were selected.
checkLimitsAndCtrlHeater(htrCtx); checkLimitsAndCtrlHeater(htrCtx);
} }
} else { } else {
// TODO: muss der Heater dann wirklich abgeschalten werden? // 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 (chooseHeater(htrCtx.switchNr, htrCtx.redSwitchNr)) {
if (heaterHandler.getSwitchState(htrCtx.switchNr)) { if (heaterCtrlAllowed() and
heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON)) {
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent);
} }
} }
} }
@ -1593,7 +1609,7 @@ bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) {
return false; return false;
} }
bool ThermalController::chooseHeater(heater::Switchers& switchNr, heater::Switchers redSwitchNr) { bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr) {
bool heaterAvailable = true; bool heaterAvailable = true;
if (heaterHandler.getHealth(switchNr) != HasHealthIF::HEALTHY) { if (heaterHandler.getHealth(switchNr) != HasHealthIF::HEALTHY) {
@ -1611,15 +1627,18 @@ bool ThermalController::chooseHeater(heater::Switchers& switchNr, heater::Switch
} }
void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) { void ThermalController::heaterCtrlTempTooHighHandler(HeaterContext& htrCtx, const char* whatLimit) {
if (not heaterCtrlAllowed()) {
return;
}
if (htrCtx.switchState == HeaterHandler::SwitchState::ON) { if (htrCtx.switchState == HeaterHandler::SwitchState::ON) {
sif::info << "TCS: Component " << static_cast<int>(thermalComponent) << " too warm, above " sif::info << "TCS: Component " << static_cast<int>(thermalComponent) << " too warm, above "
<< whatLimit << ", switching off heater" << std::endl; << whatLimit << ", switching off heater" << std::endl;
heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent);
heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].switchTransition = true;
heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF;
} }
if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == HeaterHandler::SwitchState::ON) { if (heaterHandler.getSwitchState(htrCtx.redSwitchNr) == HeaterHandler::SwitchState::ON) {
heaterHandler.switchHeater(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF); heaterSwitchHelper(htrCtx.redSwitchNr, HeaterHandler::SwitchState::OFF, thermalComponent);
heaterStates[htrCtx.redSwitchNr].switchTransition = true; heaterStates[htrCtx.redSwitchNr].switchTransition = true;
heaterStates[htrCtx.redSwitchNr].target = HeaterHandler::SwitchState::OFF; heaterStates[htrCtx.redSwitchNr].target = HeaterHandler::SwitchState::OFF;
} }
@ -1634,43 +1653,44 @@ void ThermalController::checkLimitsAndCtrlHeater(HeaterContext& htrCtx) {
if (heaterStates[htrCtx.switchNr].switchTransition) { if (heaterStates[htrCtx.switchNr].switchTransition) {
htrCtx.doHeaterHandling = false; htrCtx.doHeaterHandling = false;
heaterCtrlCheckUpperLimits(htrCtx); heaterCtrlCheckUpperLimits(htrCtx);
} else { return;
// Heater off }
htrCtx.switchState = heaterHandler.getSwitchState(htrCtx.switchNr);
if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) { htrCtx.switchState = heaterHandler.getSwitchState(htrCtx.switchNr);
if (sensorTemp < htrCtx.tempLimit.opLowerLimit) { // Heater off
heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::ON); if (htrCtx.switchState == HeaterHandler::SwitchState::OFF) {
sif::info << "ThermalController::checkLimitsAndCtrlHeater: Heater " if (sensorTemp < htrCtx.tempLimit.opLowerLimit and heaterCtrlAllowed()) {
<< static_cast<int>(thermalComponent) << " ON" << std::endl; sif::info << "TCS: Heater " << static_cast<int>(thermalComponent) << " ON" << std::endl;
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::ON, thermalComponent);
heaterStates[htrCtx.switchNr].switchTransition = true;
heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::ON;
} else {
// Even if heater control is now allowed, we can update the state.
thermalStates[thermalComponent].heating = false;
}
heaterCtrlCheckUpperLimits(htrCtx);
return;
}
// Heater on
if (htrCtx.switchState == HeaterHandler::SwitchState::ON) {
if (thermalStates[thermalComponent].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>(thermalComponent) << " OFF" << std::endl;
heaterSwitchHelper(htrCtx.switchNr, HeaterHandler::SwitchState::OFF, thermalComponent);
heaterStates[htrCtx.switchNr].switchTransition = true; heaterStates[htrCtx.switchNr].switchTransition = true;
thermalStates[thermalComponent].heating = true; heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF;
heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::ON;
} else {
thermalStates[thermalComponent].heating = false;
} }
heaterCtrlCheckUpperLimits(htrCtx); return;
// Heater on }
} else if (heaterHandler.getSwitchState(htrCtx.switchNr) == HeaterHandler::SwitchState::ON) { // This can happen if heater is used as alternative heater (no regular heating cycle), so we
if (thermalStates[thermalComponent].heating) { // should still check the upper limits.
// We are already in a heating cycle, so need to check whether heating task is complete. bool tooHighHandlerAlreadyCalled = heaterCtrlCheckUpperLimits(htrCtx);
if (sensorTemp >= htrCtx.tempLimit.opLowerLimit + TEMP_OFFSET) { if (sensorTemp >= htrCtx.tempLimit.cutOffLimit) {
heaterHandler.switchHeater(htrCtx.switchNr, HeaterHandler::SwitchState::OFF); componentAboveCutOffLimit = true;
sif::info << "ThermalController::checkLimitsAndCtrlHeater: Heater " if (not tooHighHandlerAlreadyCalled) {
<< static_cast<int>(thermalComponent) << " OFF" << std::endl; heaterCtrlTempTooHighHandler(htrCtx, "CutOff-Limit");
heaterStates[htrCtx.switchNr].switchTransition = true;
heaterStates[htrCtx.switchNr].target = HeaterHandler::SwitchState::OFF;
thermalStates[thermalComponent].heating = false;
}
} else {
// 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");
}
}
} }
} }
} }
@ -1702,8 +1722,8 @@ void ThermalController::resetSensorsArray() {
} }
thermalComponent = NONE; thermalComponent = NONE;
} }
void ThermalController::heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates) { void ThermalController::heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates) {
// TODO: Test
for (unsigned i = 0; i < 7; i++) { for (unsigned i = 0; i < 7; i++) {
if (heaterStates[i].switchTransition) { if (heaterStates[i].switchTransition) {
if (currentHeaterStates[i] == heaterStates[i].target) { if (currentHeaterStates[i] == heaterStates[i].target) {
@ -1727,11 +1747,12 @@ uint32_t ThermalController::tempFloatToU32() const {
return tempRaw; return tempRaw;
} }
void ThermalController::setMode(Mode_t mode) { void ThermalController::setMode(Mode_t mode, Submode_t submode) {
if (mode == MODE_OFF) { if (mode == MODE_OFF) {
transitionToOff = false; transitionWhenHeatersOff = false;
} }
this->mode = mode; this->mode = mode;
this->submode = submode;
modeHelper.modeChanged(mode, submode); modeHelper.modeChanged(mode, submode);
announceMode(false); announceMode(false);
} }
@ -1746,6 +1767,43 @@ bool ThermalController::tooHotHandler(object_id_t object, bool& oneShotFlag) {
return false; return false;
} }
bool ThermalController::heaterCtrlAllowed() const { return submode != SUBMODE_NO_HEATER_CTRL; }
void ThermalController::resetThermalStates() {
for (auto& thermalState : thermalStates) {
thermalState.heating = false;
}
}
void ThermalController::heaterSwitchHelper(heater::Switch switchNr,
HeaterHandler::SwitchState state,
unsigned componentIdx) {
timeval currentTime;
Clock::getClockMonotonic(&currentTime);
if (state == HeaterHandler::SwitchState::ON) {
heaterHandler.switchHeater(switchNr, state);
thermalStates[componentIdx].heating = true;
thermalStates[componentIdx].heaterStartTime = currentTime.tv_sec;
} else {
heaterHandler.switchHeater(switchNr, state);
thermalStates[componentIdx].heating = false;
thermalStates[componentIdx].heaterEndTime = currentTime.tv_sec;
}
}
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;
}
}
void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag) { void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag) {
// Clear the one shot flag is the component is in acceptable temperature range. // Clear the one shot flag is the component is in acceptable temperature range.
if (not tooHotHandler(object, oneShotFlag) and not componentAboveUpperLimit) { if (not tooHotHandler(object, oneShotFlag) and not componentAboveUpperLimit) {
@ -1755,14 +1813,15 @@ void ThermalController::tooHotHandlerWhichClearsOneShotFlag(object_id_t object,
void ThermalController::startTransition(Mode_t mode_, Submode_t submode_) { void ThermalController::startTransition(Mode_t mode_, Submode_t submode_) {
triggerEvent(CHANGING_MODE, mode_, submode_); triggerEvent(CHANGING_MODE, mode_, submode_);
if (mode_ == MODE_OFF) { // For MODE_OFF and the no heater control submode, we command all switches to off before
for (uint8_t i = 0; i < heater::Switchers::NUMBER_OF_SWITCHES; i++) { // completing the transition. This ensures a consistent state when commanding these modes.
heaterHandler.switchHeater(static_cast<heater::Switchers>(i), if ((mode_ == MODE_OFF) or ((mode_ == MODE_ON) and (submode_ == SUBMODE_NO_HEATER_CTRL))) {
HeaterHandler::SwitchState::OFF); heaterSwitchHelperAllOff();
} transitionWhenHeatersOff = true;
transitionToOff = true; targetMode = mode_;
transitionToOffCycles = 0; targetSubmode = submode_;
transitionWhenHeatersOffCycles = 0;
} else { } else {
setMode(mode_); setMode(mode_, submode_);
} }
} }

View File

@ -48,8 +48,13 @@ struct TempLimits {
struct ThermalState { struct ThermalState {
uint8_t errorCounter; uint8_t errorCounter;
bool heating; // Is heating on for that thermal module?
uint32_t heaterStartTime; bool heating = false;
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 { struct HeaterState {
@ -90,6 +95,8 @@ enum ThermalComponents : uint8_t {
class ThermalController : public ExtendedControllerBase { class ThermalController : public ExtendedControllerBase {
public: public:
static constexpr uint8_t SUBMODE_NO_HEATER_CTRL = 1;
static const uint16_t INVALID_TEMPERATURE = 999; static const uint16_t INVALID_TEMPERATURE = 999;
static const uint8_t NUMBER_OF_SENSORS = 16; static const uint8_t NUMBER_OF_SENSORS = 16;
static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80; static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80;
@ -103,13 +110,13 @@ class ThermalController : public ExtendedControllerBase {
protected: protected:
struct HeaterContext { struct HeaterContext {
public: public:
HeaterContext(heater::Switchers switchNr, heater::Switchers redundantSwitchNr, HeaterContext(heater::Switch switchNr, heater::Switch redundantSwitchNr,
const TempLimits& tempLimit) const TempLimits& tempLimit)
: switchNr(switchNr), redSwitchNr(redundantSwitchNr), tempLimit(tempLimit) {} : switchNr(switchNr), redSwitchNr(redundantSwitchNr), tempLimit(tempLimit) {}
bool doHeaterHandling = true; bool doHeaterHandling = true;
heater::Switchers switchNr; heater::Switch switchNr;
HeaterHandler::SwitchState switchState = HeaterHandler::SwitchState::OFF; HeaterHandler::SwitchState switchState = HeaterHandler::SwitchState::OFF;
heater::Switchers redSwitchNr; heater::Switch redSwitchNr;
const TempLimits& tempLimit; const TempLimits& tempLimit;
}; };
@ -263,11 +270,13 @@ class ThermalController : public ExtendedControllerBase {
bool strTooHotFlag = false; bool strTooHotFlag = false;
bool rwTooHotFlag = false; bool rwTooHotFlag = false;
bool transitionToOff = false; bool transitionWhenHeatersOff = false;
uint32_t transitionToOffCycles = 0; uint32_t transitionWhenHeatersOffCycles = 0;
Mode_t targetMode = MODE_OFF;
Submode_t targetSubmode = SUBMODE_NONE;
uint32_t cycles = 0; uint32_t cycles = 0;
std::array<ThermalState, 30> thermalStates{}; std::array<ThermalState, ThermalComponents::NUM_ENTRIES> thermalStates{};
std::array<HeaterState, 7> heaterStates{}; std::array<HeaterState, heater::NUMBER_OF_SWITCHES> heaterStates{};
// Initial delay to make sure all pool variables have been initialized their owners. // Initial delay to make sure all pool variables have been initialized their owners.
// Also, wait for system initialization to complete. // Also, wait for system initialization to complete.
@ -292,6 +301,9 @@ class ThermalController : public ExtendedControllerBase {
void startTransition(Mode_t mode, Submode_t submode) override; void startTransition(Mode_t mode, Submode_t submode) override;
bool heaterCtrlAllowed() const;
void resetThermalStates();
void resetSensorsArray(); void resetSensorsArray();
void copySensors(); void copySensors();
void copySus(); void copySus();
@ -302,9 +314,13 @@ class ThermalController : public ExtendedControllerBase {
bool heaterCtrlCheckUpperLimits(HeaterContext& heaterContext); bool heaterCtrlCheckUpperLimits(HeaterContext& heaterContext);
void heaterCtrlTempTooHighHandler(HeaterContext& heaterContext, const char* whatLimit); void heaterCtrlTempTooHighHandler(HeaterContext& heaterContext, const char* whatLimit);
bool chooseHeater(heater::Switchers& switchNr, heater::Switchers redSwitchNr); bool chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr);
bool selectAndReadSensorTemp(HeaterContext& htrCtx); bool selectAndReadSensorTemp(HeaterContext& htrCtx);
void heaterSwitchHelperAllOff();
void heaterSwitchHelper(heater::Switch switchNr, HeaterHandler::SwitchState state,
unsigned componentIdx);
void ctrlAcsBoard(); void ctrlAcsBoard();
void ctrlMgt(); void ctrlMgt();
void ctrlRw(); void ctrlRw();
@ -329,7 +345,7 @@ class ThermalController : public ExtendedControllerBase {
void ctrlMpa(); void ctrlMpa();
void ctrlScexBoard(); void ctrlScexBoard();
void heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates); void heaterTransitionControl(const HeaterSwitchStates& currentHeaterStates);
void setMode(Mode_t mode); void setMode(Mode_t mode, Submode_t submode);
uint32_t tempFloatToU32() const; uint32_t tempFloatToU32() const;
bool tooHotHandler(object_id_t object, bool& oneShotFlag); bool tooHotHandler(object_id_t object, bool& oneShotFlag);
void tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag); void tooHotHandlerWhichClearsOneShotFlag(object_id_t object, bool& oneShotFlag);

View File

@ -4,8 +4,8 @@
#include <fsfw/datapoollocal/LocalPoolVariable.h> #include <fsfw/datapoollocal/LocalPoolVariable.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h> #include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include "devices/heaterSwitcherList.h"
#include "eive/eventSubsystemIds.h" #include "eive/eventSubsystemIds.h"
#include "mission/tcs/defs.h"
namespace tcsCtrl { namespace tcsCtrl {

View File

@ -111,7 +111,7 @@ void buildNormalSequence(Subsystem& ss, ModeListEntry& eh) {
ctxc); ctxc);
// Transition 1 // Transition 1
iht(objects::THERMAL_CONTROLLER, NML, 0, TCS_TABLE_NORMAL_TRANS_1.second); iht(objects::THERMAL_CONTROLLER, HasModesIF::MODE_ON, 0, TCS_TABLE_NORMAL_TRANS_1.second);
check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TRANS_1.first, &TCS_TABLE_NORMAL_TRANS_1.second)), check(ss.addTable(TableEntry(TCS_TABLE_NORMAL_TRANS_1.first, &TCS_TABLE_NORMAL_TRANS_1.second)),
ctxc); ctxc);

View File

@ -215,17 +215,17 @@ void HeaterHandler::handleSwitchHandling() {
heaterVec[idx].cmdActive = true; heaterVec[idx].cmdActive = true;
heaterVec[idx].action = SET_SWITCH_OFF; heaterVec[idx].action = SET_SWITCH_OFF;
triggerEvent(FAULTY_HEATER_WAS_ON, idx, 0); triggerEvent(FAULTY_HEATER_WAS_ON, idx, 0);
handleSwitchOffCommand(static_cast<heater::Switchers>(idx)); handleSwitchOffCommand(static_cast<heater::Switch>(idx));
continue; continue;
} }
} }
if (heaterVec[idx].cmdActive) { if (heaterVec[idx].cmdActive) {
switch (heaterVec[idx].action) { switch (heaterVec[idx].action) {
case SET_SWITCH_ON: case SET_SWITCH_ON:
handleSwitchOnCommand(static_cast<heater::Switchers>(idx)); handleSwitchOnCommand(static_cast<heater::Switch>(idx));
break; break;
case SET_SWITCH_OFF: case SET_SWITCH_OFF:
handleSwitchOffCommand(static_cast<heater::Switchers>(idx)); handleSwitchOffCommand(static_cast<heater::Switch>(idx));
break; break;
default: default:
sif::error << "HeaterHandler::handleActiveCommands: Invalid action commanded" sif::error << "HeaterHandler::handleActiveCommands: Invalid action commanded"
@ -236,7 +236,7 @@ void HeaterHandler::handleSwitchHandling() {
} }
} }
void HeaterHandler::handleSwitchOnCommand(heater::Switchers heaterIdx) { void HeaterHandler::handleSwitchOnCommand(heater::Switch heaterIdx) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
auto& heater = heaterVec.at(heaterIdx); auto& heater = heaterVec.at(heaterIdx);
if (waitForSwitchOff) { if (waitForSwitchOff) {
@ -307,7 +307,7 @@ void HeaterHandler::handleSwitchOnCommand(heater::Switchers heaterIdx) {
} }
} }
void HeaterHandler::handleSwitchOffCommand(heater::Switchers heaterIdx) { void HeaterHandler::handleSwitchOffCommand(heater::Switch heaterIdx) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
auto& heater = heaterVec.at(heaterIdx); auto& heater = heaterVec.at(heaterIdx);
// Check whether switch is already off // Check whether switch is already off
@ -344,12 +344,12 @@ void HeaterHandler::handleSwitchOffCommand(heater::Switchers heaterIdx) {
heater.cmdActive = false; heater.cmdActive = false;
} }
HeaterHandler::SwitchState HeaterHandler::getSwitchState(heater::Switchers switchNr) const { HeaterHandler::SwitchState HeaterHandler::getSwitchState(heater::Switch switchNr) const {
MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
return heaterVec.at(switchNr).switchState; return heaterVec.at(switchNr).switchState;
} }
ReturnValue_t HeaterHandler::switchHeater(heater::Switchers heater, SwitchState switchState) { ReturnValue_t HeaterHandler::switchHeater(heater::Switch heater, SwitchState switchState) {
if (switchState == SwitchState::ON) { if (switchState == SwitchState::ON) {
return sendSwitchCommand(heater, PowerSwitchIF::SWITCH_ON); return sendSwitchCommand(heater, PowerSwitchIF::SWITCH_ON);
} else if (switchState == SwitchState::OFF) { } else if (switchState == SwitchState::OFF) {
@ -428,7 +428,7 @@ ReturnValue_t HeaterHandler::getSwitchState(uint8_t switchNr) const {
if (switchNr > 7) { if (switchNr > 7) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
if (getSwitchState(static_cast<heater::Switchers>(switchNr)) == SwitchState::ON) { if (getSwitchState(static_cast<heater::Switch>(switchNr)) == SwitchState::ON) {
return PowerSwitchIF::SWITCH_ON; return PowerSwitchIF::SWITCH_ON;
} }
return PowerSwitchIF::SWITCH_OFF; return PowerSwitchIF::SWITCH_OFF;
@ -438,7 +438,7 @@ ReturnValue_t HeaterHandler::getFuseState(uint8_t fuseNr) const { return 0; }
uint32_t HeaterHandler::getSwitchDelayMs(void) const { return 2000; } uint32_t HeaterHandler::getSwitchDelayMs(void) const { return 2000; }
HasHealthIF::HealthState HeaterHandler::getHealth(heater::Switchers heater) { HasHealthIF::HealthState HeaterHandler::getHealth(heater::Switch heater) {
auto* healthDev = heaterVec.at(heater).healthDevice; auto* healthDev = heaterVec.at(heater).healthDevice;
if (healthDev != nullptr) { if (healthDev != nullptr) {
MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX); MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);

View File

@ -20,8 +20,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "devices/heaterSwitcherList.h"
#include "events/subsystemIdRanges.h" #include "events/subsystemIdRanges.h"
#include "mission/tcs/defs.h"
#include "returnvalues/classIds.h" #include "returnvalues/classIds.h"
class PowerSwitchIF; class PowerSwitchIF;
@ -75,8 +75,8 @@ class HeaterHandler : public ExecutableObjectIF,
protected: protected:
enum SwitchAction : uint8_t { SET_SWITCH_OFF, SET_SWITCH_ON, NONE }; enum SwitchAction : uint8_t { SET_SWITCH_OFF, SET_SWITCH_ON, NONE };
ReturnValue_t switchHeater(heater::Switchers heater, SwitchState switchState); ReturnValue_t switchHeater(heater::Switch heater, SwitchState switchState);
HasHealthIF::HealthState getHealth(heater::Switchers heater); HasHealthIF::HealthState getHealth(heater::Switch heater);
ReturnValue_t performOperation(uint8_t operationCode = 0) override; ReturnValue_t performOperation(uint8_t operationCode = 0) override;
@ -174,7 +174,7 @@ class HeaterHandler : public ExecutableObjectIF,
* @brief Returns the state of a switch (ON - true, or OFF - false). * @brief Returns the state of a switch (ON - true, or OFF - false).
* @param switchNr The number of the switch to check. * @param switchNr The number of the switch to check.
*/ */
SwitchState getSwitchState(heater::Switchers switchNr) const; SwitchState getSwitchState(heater::Switch switchNr) const;
/** /**
* @brief This function runs commands waiting for execution. * @brief This function runs commands waiting for execution.
@ -198,9 +198,9 @@ class HeaterHandler : public ExecutableObjectIF,
const HasModesIF& getModeIF() const override; const HasModesIF& getModeIF() const override;
ModeTreeChildIF& getModeTreeChildIF() override; ModeTreeChildIF& getModeTreeChildIF() override;
void handleSwitchOnCommand(heater::Switchers heaterIdx); void handleSwitchOnCommand(heater::Switch heaterIdx);
void handleSwitchOffCommand(heater::Switchers heaterIdx); void handleSwitchOffCommand(heater::Switch heaterIdx);
/** /**
* @brief Checks if all switches are off. * @brief Checks if all switches are off.

View File

@ -1,6 +1,21 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <cstdint>
namespace heater {
enum Switch : uint8_t {
HEATER_0_OBC_BRD,
HEATER_1_PLOC_PROC_BRD,
HEATER_2_ACS_BRD,
HEATER_3_PCDU_PDU,
HEATER_4_CAMERA,
HEATER_5_STR,
HEATER_6_DRO,
HEATER_7_S_BAND,
NUMBER_OF_SWITCHES
};
}
namespace tcs { namespace tcs {

View File

@ -48,7 +48,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") {
CommandMessage modeMessage; CommandMessage modeMessage;
ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND, ModeMessage::setModeMessage(&modeMessage, ModeMessage::CMD_MODE_COMMAND,
ControllerBase::MODE_NORMAL, HasModesIF::SUBMODE_NONE); HasModesIF::MODE_ON, HasModesIF::SUBMODE_NONE);
MessageQueueIF* commandQueue = MessageQueueIF* commandQueue =
QueueFactory::instance()->createMessageQueue(5, MessageQueueMessage::MAX_MESSAGE_SIZE); QueueFactory::instance()->createMessageQueue(5, MessageQueueMessage::MAX_MESSAGE_SIZE);
@ -58,7 +58,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") {
REQUIRE(controller.performOperation(0) == returnvalue::OK); REQUIRE(controller.performOperation(0) == returnvalue::OK);
REQUIRE(testEnvironment::eventManager->isEventInEventList( REQUIRE(testEnvironment::eventManager->isEventInEventList(
THERMAL_CONTROLLER_ID, HasModesIF::MODE_INFO, ControllerBase::MODE_NORMAL, THERMAL_CONTROLLER_ID, HasModesIF::MODE_INFO, HasModesIF::MODE_ON,
HasModesIF::SUBMODE_NONE) == true); HasModesIF::SUBMODE_NONE) == true);
QueueFactory::instance()->deleteMessageQueue(commandQueue); QueueFactory::instance()->deleteMessageQueue(commandQueue);