Merge remote-tracking branch 'origin/develop' into mueller/acs-ss-init
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good

This commit is contained in:
2022-05-16 15:11:24 +02:00
23 changed files with 509 additions and 341 deletions

View File

@ -4,6 +4,7 @@
#include <fsfw/health/HealthTable.h>
#include <fsfw/internalerror/InternalErrorReporter.h>
#include <fsfw/pus/CService200ModeCommanding.h>
#include <fsfw/pus/CService201HealthCommanding.h>
#include <fsfw/pus/Service17Test.h>
#include <fsfw/pus/Service1TelecommandVerification.h>
#include <fsfw/pus/Service20ParameterManagement.h>
@ -44,10 +45,13 @@
#define OBSW_TM_TO_PTME 0
#endif
void ObjectFactory::produceGenericObjects() {
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_) {
// Framework objects
new EventManager(objects::EVENT_MANAGER);
new HealthTable(objects::HEALTH_TABLE);
auto healthTable = new HealthTable(objects::HEALTH_TABLE);
if (healthTable != nullptr) {
*healthTable_ = healthTable;
}
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
new TimeStamper(objects::TIME_STAMPER);
@ -96,8 +100,9 @@ void ObjectFactory::produceGenericObjects() {
new Service20ParameterManagement(objects::PUS_SERVICE_20_PARAMETERS, apid::EIVE_OBSW,
pus::PUS_SERVICE_20);
new CService200ModeCommanding(objects::PUS_SERVICE_200_MODE_MGMT, apid::EIVE_OBSW,
pus::PUS_SERVICE_200, 8, config::LONGEST_MODE_TIMEOUT_SECONDS);
pus::PUS_SERVICE_200, 8);
new CService201HealthCommanding(objects::PUS_SERVICE_201_HEALTH, apid::EIVE_OBSW,
pus::PUS_SERVICE_201);
#if OBSW_ADD_TCPIP_BRIDGE == 1
#if OBSW_USE_TMTC_TCP_BRIDGE == 0
auto tmtcBridge = new UdpTmTcBridge(objects::TMTC_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR);

View File

@ -1,9 +1,11 @@
#ifndef MISSION_CORE_GENERICFACTORY_H_
#define MISSION_CORE_GENERICFACTORY_H_
class HealthTableIF;
namespace ObjectFactory {
void produceGenericObjects();
void produceGenericObjects(HealthTableIF** healthTable = nullptr);
}

View File

@ -1,21 +1,38 @@
#include "HeaterHandler.h"
#include <fsfw/health/HealthTableIF.h>
#include <fsfw/ipc/QueueFactory.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
#include <stdexcept>
#include "devices/gpioIds.h"
#include "devices/powerSwitcherList.h"
HeaterHandler::HeaterHandler(object_id_t setObjectId_, object_id_t gpioDriverId_,
CookieIF* gpioCookie_, object_id_t mainLineSwitcherObjectId_,
uint8_t mainLineSwitch_)
HeaterHandler::HeaterHandler(object_id_t setObjectId_, GpioIF* gpioInterface_, HeaterHelper helper,
PowerSwitchIF* mainLineSwitcher_, power::Switch_t mainLineSwitch_)
: SystemObject(setObjectId_),
gpioDriverId(gpioDriverId_),
gpioCookie(gpioCookie_),
mainLineSwitcherObjectId(mainLineSwitcherObjectId_),
helper(helper),
gpioInterface(gpioInterface_),
mainLineSwitcher(mainLineSwitcher_),
mainLineSwitch(mainLineSwitch_),
actionHelper(this, nullptr) {
for (const auto& heater : helper.heaters) {
if (heater.first == nullptr) {
throw std::invalid_argument("HeaterHandler::HeaterHandler: Invalid Heater Object");
}
}
if (gpioInterface_ == nullptr) {
throw std::invalid_argument("HeaterHandler::HeaterHandler: Invalid Gpio IF");
}
if (mainLineSwitcher == nullptr) {
throw std::invalid_argument("HeaterHandler::HeaterHandler: Invalid PowerSwitchIF");
}
heaterMutex = MutexFactory::instance()->createMutex();
if (heaterMutex == nullptr) {
throw std::runtime_error("HeaterHandler::HeaterHandler: Creating Mutex failed");
}
auto mqArgs = MqArgs(setObjectId_, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
@ -24,10 +41,16 @@ HeaterHandler::HeaterHandler(object_id_t setObjectId_, object_id_t gpioDriverId_
HeaterHandler::~HeaterHandler() {}
ReturnValue_t HeaterHandler::performOperation(uint8_t operationCode) {
if (operationCode == DeviceHandlerIF::PERFORM_OPERATION) {
try {
readCommandQueue();
handleActiveCommands();
return RETURN_OK;
for (const auto& heater : helper.heaters) {
heater.first->performOperation(0);
}
handleSwitchHandling();
} catch (const std::out_of_range& e) {
sif::warning << "HeaterHandler::performOperation: "
"Out of range error | "
<< e.what() << std::endl;
}
return RETURN_OK;
}
@ -43,33 +66,12 @@ ReturnValue_t HeaterHandler::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
gpioInterface = ObjectManager::instance()->get<GpioIF>(gpioDriverId);
if (gpioInterface == nullptr) {
sif::error << "HeaterHandler::initialize: Invalid Gpio interface." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != RETURN_OK) {
sif::error << "HeaterHandler::initialize: Failed to initialize Gpio interface" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
IPCStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == nullptr) {
ipcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == nullptr) {
sif::error << "HeaterHandler::initialize: IPC store not set up in factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
if (mainLineSwitcherObjectId != objects::NO_OBJECT) {
mainLineSwitcher = ObjectManager::instance()->get<PowerSwitchIF>(mainLineSwitcherObjectId);
if (mainLineSwitcher == nullptr) {
sif::error << "HeaterHandler::initialize: Failed to get main line switcher. Make sure "
<< "main line switcher object is initialized." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
}
result = actionHelper.initialize(commandQueue);
if (result != RETURN_OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
@ -79,81 +81,97 @@ ReturnValue_t HeaterHandler::initialize() {
}
ReturnValue_t HeaterHandler::initializeHeaterMap() {
HeaterCommandInfo_t heaterCommandInfo;
for (switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
std::pair status = heaterMap.emplace(switchNr, heaterCommandInfo);
if (status.second == false) {
sif::error << "HeaterHandler::initializeHeaterMap: Failed to initialize heater map"
<< std::endl;
return RETURN_FAILED;
}
for (power::Switch_t switchNr = 0; switchNr < heater::NUMBER_OF_SWITCHES; switchNr++) {
heaterVec.push_back(HeaterWrapper(helper.heaters[switchNr], SwitchState::OFF));
}
return RETURN_OK;
}
void HeaterHandler::setInitialSwitchStates() {
for (switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
switchStates[switchNr] = OFF;
}
}
void HeaterHandler::readCommandQueue() {
ReturnValue_t result = RETURN_OK;
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) {
return;
}
result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) {
return;
}
do {
result = commandQueue->receiveMessage(&command);
if (result == MessageQueueIF::EMPTY) {
break;
} else if (result != RETURN_OK) {
sif::warning << "HeaterHandler::readCommandQueue: Message reception error" << std::endl;
}
result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) {
continue;
}
} while (result == RETURN_OK);
}
ReturnValue_t HeaterHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result;
if (actionId != SWITCH_HEATER) {
result = COMMAND_NOT_SUPPORTED;
} else {
switchNr_t switchNr = *data;
HeaterMapIter heaterMapIter = heaterMap.find(switchNr);
if (heaterMapIter != heaterMap.end()) {
if (heaterMapIter->second.active) {
return COMMAND_ALREADY_WAITING;
}
heaterMapIter->second.action = *(data + 1);
heaterMapIter->second.active = true;
heaterMapIter->second.replyQueue = commandedBy;
} else {
sif::error << "HeaterHandler::executeAction: Invalid switchNr" << std::endl;
return INVALID_SWITCH_NR;
}
result = RETURN_OK;
if (data == nullptr or size < 3) {
return HasActionsIF::INVALID_PARAMETERS;
}
return result;
if (actionId != SWITCH_HEATER) {
return COMMAND_NOT_SUPPORTED;
}
auto switchNr = data[0];
if (switchNr > 7) {
return HasActionsIF::INVALID_PARAMETERS;
}
auto& heater = heaterVec.at(switchNr);
auto actionRaw = data[1];
if (actionRaw != 0 and actionRaw != 1) {
return HasActionsIF::INVALID_PARAMETERS;
}
auto action = static_cast<SwitchAction>(data[1]);
// Always accepts OFF commands
if (action == SwitchAction::SET_SWITCH_ON) {
HasHealthIF::HealthState health = heater.healthDevice->getHealth();
if (health == HasHealthIF::FAULTY or health == HasHealthIF::PERMANENT_FAULTY or
health == HasHealthIF::NEEDS_RECOVERY) {
return HasHealthIF::OBJECT_NOT_HEALTHY;
}
CmdSourceParam cmdSource = CmdSourceParam::EXTERNAL;
uint8_t cmdSourceRaw = data[2];
if (cmdSourceRaw > 1) {
return HasActionsIF::INVALID_PARAMETERS;
}
cmdSource = static_cast<CmdSourceParam>(data[2]);
if (health == HasHealthIF::EXTERNAL_CONTROL and cmdSource == CmdSourceParam::INTERNAL) {
return HasHealthIF::IS_EXTERNALLY_CONTROLLED;
}
}
if (heater.cmdActive) {
return COMMAND_ALREADY_WAITING;
}
heater.action = action;
heater.cmdActive = true;
heater.replyQueue = commandedBy;
return RETURN_OK;
}
ReturnValue_t HeaterHandler::sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) {
ReturnValue_t result;
store_address_t storeAddress;
uint8_t commandData[2];
uint8_t commandData[3] = {};
switch (onOff) {
case PowerSwitchIF::SWITCH_ON:
commandData[0] = switchNr;
commandData[1] = SET_SWITCH_ON;
commandData[2] = CmdSourceParam::INTERNAL;
break;
case PowerSwitchIF::SWITCH_OFF:
commandData[0] = switchNr;
commandData[1] = SET_SWITCH_OFF;
commandData[2] = CmdSourceParam::INTERNAL;
break;
default:
sif::error << "HeaterHandler::sendSwitchCommand: Invalid switch request" << std::endl;
break;
}
result = IPCStore->addData(&storeAddress, commandData, sizeof(commandData));
result = ipcStore->addData(&storeAddress, commandData, sizeof(commandData));
if (result == RETURN_OK) {
CommandMessage message;
ActionMessage::setCommand(&message, SWITCH_HEATER, storeAddress);
@ -167,16 +185,27 @@ ReturnValue_t HeaterHandler::sendSwitchCommand(uint8_t switchNr, ReturnValue_t o
return result;
}
void HeaterHandler::handleActiveCommands() {
HeaterMapIter heaterMapIter = heaterMap.begin();
for (; heaterMapIter != heaterMap.end(); heaterMapIter++) {
if (heaterMapIter->second.active) {
switch (heaterMapIter->second.action) {
void HeaterHandler::handleSwitchHandling() {
for (uint8_t idx = 0; idx < heater::NUMBER_OF_SWITCHES; idx++) {
auto health = heaterVec[idx].healthDevice->getHealth();
if (heaterVec[idx].switchState == SwitchState::ON) {
// If a heater is still on but the device was marked faulty by the operator, the SW
// will shut down the heater
if (health == HasHealthIF::FAULTY or health == HasHealthIF::PERMANENT_FAULTY) {
heaterVec[idx].cmdActive = true;
heaterVec[idx].action = SET_SWITCH_OFF;
triggerEvent(FAULTY_HEATER_WAS_ON, idx, 0);
handleSwitchOffCommand(static_cast<heater::Switchers>(idx));
continue;
}
}
if (heaterVec[idx].cmdActive) {
switch (heaterVec[idx].action) {
case SET_SWITCH_ON:
handleSwitchOnCommand(heaterMapIter);
handleSwitchOnCommand(static_cast<heater::Switchers>(idx));
break;
case SET_SWITCH_OFF:
handleSwitchOffCommand(heaterMapIter);
handleSwitchOffCommand(static_cast<heater::Switchers>(idx));
break;
default:
sif::error << "HeaterHandler::handleActiveCommands: Invalid action commanded"
@ -187,162 +216,139 @@ void HeaterHandler::handleActiveCommands() {
}
}
void HeaterHandler::handleSwitchOnCommand(HeaterMapIter heaterMapIter) {
void HeaterHandler::handleSwitchOnCommand(heater::Switchers heaterIdx) {
ReturnValue_t result = RETURN_OK;
switchNr_t switchNr;
auto& heater = heaterVec.at(heaterIdx);
/* Check if command waits for main switch being set on and whether the timeout has expired */
if (heaterMapIter->second.waitMainSwitchOn &&
heaterMapIter->second.mainSwitchCountdown.hasTimedOut()) {
if (heater.waitMainSwitchOn && heater.mainSwitchCountdown.hasTimedOut()) {
// TODO - This requires the initiation of an FDIR procedure
triggerEvent(MAIN_SWITCH_TIMEOUT);
sif::error << "HeaterHandler::handleSwitchOnCommand: Main switch setting on timeout"
<< std::endl;
heaterMapIter->second.active = false;
heaterMapIter->second.waitMainSwitchOn = false;
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
MAIN_SWITCH_SET_TIMEOUT);
heater.cmdActive = false;
heater.waitMainSwitchOn = false;
if (heater.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heater.replyQueue, heater.action, MAIN_SWITCH_SET_TIMEOUT);
}
return;
}
switchNr = heaterMapIter->first;
/* Check state of main line switch */
// Check state of main line switch
ReturnValue_t mainSwitchState = mainLineSwitcher->getSwitchState(mainLineSwitch);
if (mainSwitchState == PowerSwitchIF::SWITCH_ON) {
if (!checkSwitchState(switchNr)) {
gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr);
if (checkSwitchState(heaterIdx) == SwitchState::OFF) {
gpioId_t gpioId = heater.gpioId;
result = gpioInterface->pullHigh(gpioId);
if (result != RETURN_OK) {
sif::error << "HeaterHandler::handleSwitchOnCommand: Failed to pull gpio with id " << gpioId
<< " high" << std::endl;
triggerEvent(GPIO_PULL_HIGH_FAILED, result);
} else {
switchStates[switchNr] = ON;
triggerEvent(HEATER_WENT_ON, heaterIdx, 0);
heater.switchState = ON;
}
} else {
triggerEvent(SWITCH_ALREADY_ON, switchNr);
triggerEvent(SWITCH_ALREADY_ON, heaterIdx);
}
/* There is no need to send action finish replies if the sender was the
* HeaterHandler itself. */
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
// There is no need to send action finish replies if the sender was the
// HeaterHandler itself
if (heater.replyQueue != commandQueue->getId()) {
if (result == RETURN_OK) {
actionHelper.finish(true, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
result);
actionHelper.finish(true, heater.replyQueue, heater.action, result);
} else {
actionHelper.finish(false, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
result);
actionHelper.finish(false, heater.replyQueue, heater.action, result);
}
}
heaterMapIter->second.active = false;
heaterMapIter->second.waitMainSwitchOn = false;
} else if (mainSwitchState == PowerSwitchIF::SWITCH_OFF &&
heaterMapIter->second.waitMainSwitchOn) {
/* Just waiting for the main switch being set on */
heater.cmdActive = false;
heater.waitMainSwitchOn = false;
} else if (mainSwitchState == PowerSwitchIF::SWITCH_OFF && heater.waitMainSwitchOn) {
// Just waiting for the main switch being set on
return;
} else if (mainSwitchState == PowerSwitchIF::SWITCH_OFF) {
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_ON);
heaterMapIter->second.mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
heaterMapIter->second.waitMainSwitchOn = true;
heater.mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
heater.waitMainSwitchOn = true;
} else {
sif::debug << "HeaterHandler::handleActiveCommands: Failed to get state of"
sif::debug << "HeaterHandler::handleSwitchHandling: Failed to get state of"
<< " main line switch" << std::endl;
if (heaterMapIter->second.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
mainSwitchState);
if (heater.replyQueue != commandQueue->getId()) {
actionHelper.finish(false, heater.replyQueue, heater.action, mainSwitchState);
}
heaterMapIter->second.active = false;
heater.cmdActive = false;
}
}
void HeaterHandler::handleSwitchOffCommand(HeaterMapIter heaterMapIter) {
void HeaterHandler::handleSwitchOffCommand(heater::Switchers heaterIdx) {
ReturnValue_t result = RETURN_OK;
switchNr_t switchNr = heaterMapIter->first;
/* Check whether switch is already off */
if (checkSwitchState(switchNr)) {
gpioId_t gpioId = getGpioIdFromSwitchNr(switchNr);
auto& heater = heaterVec.at(heaterIdx);
// Check whether switch is already off
if (checkSwitchState(heaterIdx)) {
gpioId_t gpioId = heater.gpioId;
result = gpioInterface->pullLow(gpioId);
if (result != RETURN_OK) {
sif::error << "HeaterHandler::handleSwitchOffCommand: Failed to pull gpio with id" << gpioId
<< " low" << std::endl;
triggerEvent(GPIO_PULL_LOW_FAILED, result);
} else {
switchStates[switchNr] = OFF;
/* When all switches are off, also main line switch will be turned off */
auto result = heaterMutex->lockMutex();
heater.switchState = OFF;
if (result == HasReturnvaluesIF::RETURN_OK) {
heaterMutex->unlockMutex();
}
triggerEvent(HEATER_WENT_OFF, heaterIdx, 0);
// When all switches are off, also main line switch will be turned off
if (allSwitchesOff()) {
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
}
}
} else {
sif::info << "HeaterHandler::handleSwitchOffCommand: Switch already off" << std::endl;
triggerEvent(SWITCH_ALREADY_OFF, switchNr);
triggerEvent(SWITCH_ALREADY_OFF, heaterIdx);
}
if (heaterMapIter->second.replyQueue != NO_COMMANDER) {
/* Report back switch command reply if necessary */
if (heater.replyQueue != NO_COMMANDER) {
// Report back switch command reply if necessary
if (result == HasReturnvaluesIF::RETURN_OK) {
actionHelper.finish(true, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
result);
actionHelper.finish(true, heater.replyQueue, heater.action, result);
} else {
actionHelper.finish(false, heaterMapIter->second.replyQueue, heaterMapIter->second.action,
result);
actionHelper.finish(false, heater.replyQueue, heater.action, result);
}
}
heaterMapIter->second.active = false;
heater.cmdActive = false;
}
bool HeaterHandler::checkSwitchState(int switchNr) { return switchStates[switchNr]; }
HeaterHandler::SwitchState HeaterHandler::checkSwitchState(heater::Switchers switchNr) const {
MutexGuard mg(heaterMutex);
return heaterVec.at(switchNr).switchState;
}
bool HeaterHandler::allSwitchesOff() {
bool allSwitchesOrd = false;
MutexGuard mg(heaterMutex);
/* Or all switches. As soon one switch is on, allSwitchesOrd will be true */
for (switchNr_t switchNr = 0; switchNr < heaterSwitches::NUMBER_OF_SWITCHES; switchNr++) {
allSwitchesOrd = allSwitchesOrd || switchStates[switchNr];
for (power::Switch_t switchNr = 0; switchNr < heater::NUMBER_OF_SWITCHES; switchNr++) {
allSwitchesOrd = allSwitchesOrd || heaterVec.at(switchNr).switchState;
}
return !allSwitchesOrd;
}
gpioId_t HeaterHandler::getGpioIdFromSwitchNr(int switchNr) {
gpioId_t gpioId = 0xFFFF;
switch (switchNr) {
case heaterSwitches::HEATER_0:
gpioId = gpioIds::HEATER_0;
break;
case heaterSwitches::HEATER_1:
gpioId = gpioIds::HEATER_1;
break;
case heaterSwitches::HEATER_2:
gpioId = gpioIds::HEATER_2;
break;
case heaterSwitches::HEATER_3:
gpioId = gpioIds::HEATER_3;
break;
case heaterSwitches::HEATER_4:
gpioId = gpioIds::HEATER_4;
break;
case heaterSwitches::HEATER_5:
gpioId = gpioIds::HEATER_5;
break;
case heaterSwitches::HEATER_6:
gpioId = gpioIds::HEATER_6;
break;
case heaterSwitches::HEATER_7:
gpioId = gpioIds::HEATER_7;
break;
default:
sif::error << "HeaterHandler::getGpioIdFromSwitchNr: Unknown heater switch number"
<< std::endl;
break;
}
return gpioId;
}
MessageQueueId_t HeaterHandler::getCommandQueue() const { return commandQueue->getId(); }
ReturnValue_t HeaterHandler::sendFuseOnCommand(uint8_t fuseNr) { return RETURN_OK; }
ReturnValue_t HeaterHandler::getSwitchState(uint8_t switchNr) const { return 0; }
ReturnValue_t HeaterHandler::getSwitchState(uint8_t switchNr) const {
ReturnValue_t mainSwitchState = mainLineSwitcher->getSwitchState(mainLineSwitch);
if (mainSwitchState == PowerSwitchIF::SWITCH_OFF) {
return PowerSwitchIF::SWITCH_OFF;
}
if (switchNr > 7) {
return PowerSwitchIF::RETURN_FAILED;
}
if (checkSwitchState(static_cast<heater::Switchers>(switchNr)) == SwitchState::ON) {
return PowerSwitchIF::SWITCH_ON;
}
return PowerSwitchIF::SWITCH_OFF;
}
ReturnValue_t HeaterHandler::getFuseState(uint8_t fuseNr) const { return 0; }
uint32_t HeaterHandler::getSwitchDelayMs(void) const { return 0; }
uint32_t HeaterHandler::getSwitchDelayMs(void) const { return 2000; }

View File

@ -4,6 +4,9 @@
#include <fsfw/action/HasActionsIF.h>
#include <fsfw/devicehandlers/CookieIF.h>
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
#include <fsfw/devicehandlers/HealthDevice.h>
#include <fsfw/health/HasHealthIF.h>
#include <fsfw/health/HealthHelper.h>
#include <fsfw/objectmanager/SystemObject.h>
#include <fsfw/power/PowerSwitchIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
@ -11,10 +14,20 @@
#include <fsfw/timemanager/Countdown.h>
#include <fsfw_hal/common/gpio/GpioIF.h>
#include <unordered_map>
#include <vector>
#include "devices/heaterSwitcherList.h"
class PowerSwitchIF;
class HealthTableIF;
using HeaterPair = std::pair<HealthDevice*, gpioId_t>;
struct HeaterHelper {
public:
HeaterHelper(std::array<HeaterPair, heater::NUMBER_OF_SWITCHES> heaters) : heaters(heaters) {}
std::array<HeaterPair, heater::NUMBER_OF_SWITCHES> heaters = {};
};
/**
* @brief This class intends the control of heaters.
*
@ -33,42 +46,49 @@ class HeaterHandler : public ExecutableObjectIF,
static const ReturnValue_t MAIN_SWITCH_SET_TIMEOUT = MAKE_RETURN_CODE(0xA4);
static const ReturnValue_t COMMAND_ALREADY_WAITING = MAKE_RETURN_CODE(0xA5);
enum CmdSourceParam : uint8_t { INTERNAL = 0, EXTERNAL = 1 };
/** Device command IDs */
static const DeviceCommandId_t SWITCH_HEATER = 0x0;
HeaterHandler(object_id_t setObjectId, object_id_t gpioDriverId, CookieIF* gpioCookie,
object_id_t mainLineSwitcherObjectId, uint8_t mainLineSwitch);
HeaterHandler(object_id_t setObjectId, GpioIF* gpioInterface_, HeaterHelper helper,
PowerSwitchIF* mainLineSwitcherObjectId, power::Switch_t mainLineSwitch);
virtual ~HeaterHandler();
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override;
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
virtual ReturnValue_t sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) override;
virtual ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
ReturnValue_t sendSwitchCommand(uint8_t switchNr, ReturnValue_t onOff) override;
ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override;
/**
* @brief This function will be called from the Heater object to check
* the current switch state.
*/
virtual ReturnValue_t getSwitchState(uint8_t switchNr) const override;
virtual ReturnValue_t getFuseState(uint8_t fuseNr) const override;
virtual uint32_t getSwitchDelayMs(void) const override;
ReturnValue_t getSwitchState(uint8_t switchNr) const override;
ReturnValue_t getFuseState(uint8_t fuseNr) const override;
uint32_t getSwitchDelayMs(void) const override;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
virtual ReturnValue_t initialize() override;
MessageQueueId_t getCommandQueue() const override;
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) override;
ReturnValue_t initialize() override;
private:
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HEATER_HANDLER;
static const Event GPIO_PULL_HIGH_FAILED = MAKE_EVENT(0, severity::LOW);
static const Event GPIO_PULL_LOW_FAILED = MAKE_EVENT(1, severity::LOW);
static const Event SWITCH_ALREADY_ON = MAKE_EVENT(2, severity::LOW);
static const Event SWITCH_ALREADY_OFF = MAKE_EVENT(3, severity::LOW);
static const Event MAIN_SWITCH_TIMEOUT = MAKE_EVENT(4, severity::LOW);
static constexpr Event GPIO_PULL_HIGH_FAILED = MAKE_EVENT(0, severity::LOW);
static constexpr Event GPIO_PULL_LOW_FAILED = MAKE_EVENT(1, severity::LOW);
static constexpr Event HEATER_WENT_ON = event::makeEvent(SUBSYSTEM_ID, 2, severity::INFO);
static constexpr Event HEATER_WENT_OFF = event::makeEvent(SUBSYSTEM_ID, 3, severity::INFO);
static constexpr Event SWITCH_ALREADY_ON = MAKE_EVENT(4, severity::LOW);
static constexpr Event SWITCH_ALREADY_OFF = MAKE_EVENT(5, severity::LOW);
static constexpr Event MAIN_SWITCH_TIMEOUT = MAKE_EVENT(6, severity::MEDIUM);
//! A faulty heater was one. The SW will autonomously attempt to shut it down. P1: Heater Index
static constexpr Event FAULTY_HEATER_WAS_ON = event::makeEvent(SUBSYSTEM_ID, 7, severity::LOW);
static const MessageQueueId_t NO_COMMANDER = 0;
enum SwitchState : bool { ON = true, OFF = false };
enum SwitchAction : uint8_t { SET_SWITCH_OFF, SET_SWITCH_ON, NONE };
/**
* @brief Struct holding information about a heater command to execute.
@ -80,54 +100,46 @@ class HeaterHandler : public ExecutableObjectIF,
* @param waitSwitchOn True if the command is waiting for the main switch being set on.
* @param mainSwitchCountdown Sets timeout to wait for main switch being set on.
*/
typedef struct HeaterCommandInfo {
uint8_t action;
MessageQueueId_t replyQueue;
bool active = false;
struct HeaterWrapper {
HeaterWrapper(HeaterPair pair, SwitchState initState)
: healthDevice(pair.first), gpioId(pair.second), switchState(initState) {}
HealthDevice* healthDevice = nullptr;
gpioId_t gpioId = gpio::NO_GPIO;
SwitchAction action = SwitchAction::NONE;
MessageQueueId_t replyQueue = MessageQueueIF::NO_QUEUE;
bool cmdActive = false;
SwitchState switchState = SwitchState::OFF;
bool waitMainSwitchOn = false;
Countdown mainSwitchCountdown;
} HeaterCommandInfo_t;
};
enum SwitchAction { SET_SWITCH_OFF, SET_SWITCH_ON };
using HeaterMap = std::vector<HeaterWrapper>;
using switchNr_t = uint8_t;
using HeaterMap = std::unordered_map<switchNr_t, HeaterCommandInfo_t>;
using HeaterMapIter = HeaterMap::iterator;
HeaterMap heaterVec = {};
HeaterMap heaterMap;
MutexIF* heaterMutex = nullptr;
bool switchStates[heaterSwitches::NUMBER_OF_SWITCHES];
HeaterHelper helper;
/** Size of command queue */
size_t cmdQueueSize = 20;
/**
* The object ID of the GPIO driver which enables and disables the
* heaters.
*/
object_id_t gpioDriverId;
CookieIF* gpioCookie;
GpioIF* gpioInterface = nullptr;
/** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr;
object_id_t mainLineSwitcherObjectId;
/** Switch number of the heater power supply switch */
uint8_t mainLineSwitch;
/**
* Power switcher object which controls the 8V main line of the heater
* logic on the TCS board.
*/
PowerSwitchIF* mainLineSwitcher = nullptr;
/** Switch number of the heater power supply switch */
power::Switch_t mainLineSwitch;
ActionHelper actionHelper;
StorageManagerIF* IPCStore = nullptr;
StorageManagerIF* ipcStore = nullptr;
void readCommandQueue();
@ -135,18 +147,12 @@ class HeaterHandler : public ExecutableObjectIF,
* @brief Returns the state of a switch (ON - true, or OFF - false).
* @param switchNr The number of the switch to check.
*/
bool checkSwitchState(int switchNr);
/**
* @brief Returns the ID of the GPIO related to a heater identified by the switch number
* which is defined in the heaterSwitches list.
*/
gpioId_t getGpioIdFromSwitchNr(int switchNr);
SwitchState checkSwitchState(heater::Switchers switchNr) const;
/**
* @brief This function runs commands waiting for execution.
*/
void handleActiveCommands();
void handleSwitchHandling();
ReturnValue_t initializeHeaterMap();
@ -155,9 +161,9 @@ class HeaterHandler : public ExecutableObjectIF,
*/
void setInitialSwitchStates();
void handleSwitchOnCommand(HeaterMapIter heaterMapIter);
void handleSwitchOnCommand(heater::Switchers heaterIdx);
void handleSwitchOffCommand(HeaterMapIter heaterMapIter);
void handleSwitchOffCommand(heater::Switchers heaterIdx);
/**
* @brief Checks if all switches are off.