2021-07-13 20:22:54 +02:00
|
|
|
#include "fsfw/subsystem/SubsystemBase.h"
|
2021-06-05 19:52:38 +02:00
|
|
|
|
2022-09-29 16:47:23 +02:00
|
|
|
#include "fsfw/FSFW.h"
|
2021-07-13 20:22:54 +02:00
|
|
|
#include "fsfw/ipc/QueueFactory.h"
|
2022-02-02 10:29:30 +01:00
|
|
|
#include "fsfw/objectmanager/ObjectManager.h"
|
2022-09-29 16:47:23 +02:00
|
|
|
#include "fsfw/serviceinterface.h"
|
2022-09-29 19:39:37 +02:00
|
|
|
#include "fsfw/subsystem/helper.h"
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2022-09-29 19:39:37 +02:00
|
|
|
SubsystemBase::SubsystemBase(object_id_t setObjectId, Mode_t initialMode,
|
2022-02-02 10:29:30 +01:00
|
|
|
uint16_t commandQueueDepth)
|
|
|
|
: SystemObject(setObjectId),
|
|
|
|
mode(initialMode),
|
|
|
|
healthHelper(this, setObjectId),
|
2022-09-29 19:39:37 +02:00
|
|
|
modeHelper(this) {
|
2022-02-19 16:14:02 +01:00
|
|
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
2022-02-22 10:17:56 +01:00
|
|
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
|
|
|
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
2022-02-19 16:14:02 +01:00
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
|
|
|
Submode_t targetSubmode) {
|
|
|
|
std::map<object_id_t, ChildInfo>::iterator childIter;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
for (; tableIter.value != NULL; ++tableIter) {
|
|
|
|
object_id_t object = tableIter.value->getObject();
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if ((childIter = childrenMap.find(object)) == childrenMap.end()) {
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (childIter->second.mode != tableIter.value->getMode()) {
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
Submode_t submodeToCheckAgainst = tableIter.value->getSubmode();
|
|
|
|
if (tableIter.value->inheritSubmode()) {
|
|
|
|
submodeToCheckAgainst = targetSubmode;
|
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
if (childIter->second.submode != submodeToCheckAgainst) {
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submode_t targetSubmode) {
|
|
|
|
CommandMessage command;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
std::map<object_id_t, ChildInfo>::iterator iter;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
commandsOutstanding = 0;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
for (; tableIter.value != nullptr; ++tableIter) {
|
|
|
|
object_id_t object = tableIter.value->getObject();
|
|
|
|
if ((iter = childrenMap.find(object)) == childrenMap.end()) {
|
|
|
|
// illegal table entry, should only happen due to misconfigured mode table
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2022-09-29 19:39:37 +02:00
|
|
|
sif::debug << std::hex << SystemObject::getObjectId() << ": invalid mode table entry"
|
|
|
|
<< std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Submode_t submodeToCommand = tableIter.value->getSubmode();
|
|
|
|
if (tableIter.value->inheritSubmode()) {
|
|
|
|
submodeToCommand = targetSubmode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (healthHelper.healthTable->hasHealth(object)) {
|
|
|
|
if (healthHelper.healthTable->isFaulty(object)) {
|
|
|
|
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF,
|
|
|
|
SUBMODE_NONE);
|
|
|
|
} else {
|
|
|
|
if (modeHelper.isForced()) {
|
|
|
|
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND_FORCED,
|
|
|
|
tableIter.value->getMode(), submodeToCommand);
|
|
|
|
} else {
|
|
|
|
if (healthHelper.healthTable->isCommandable(object)) {
|
|
|
|
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND,
|
|
|
|
tableIter.value->getMode(), submodeToCommand);
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND,
|
|
|
|
tableIter.value->getMode(), submodeToCommand);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((iter->second.mode == ModeMessage::getMode(&command)) &&
|
|
|
|
(iter->second.submode == ModeMessage::getSubmode(&command)) && !modeHelper.isForced()) {
|
|
|
|
continue; // don't send redundant mode commands (produces event spam), but still command if
|
|
|
|
// mode is forced to reach lower levels
|
|
|
|
}
|
|
|
|
ReturnValue_t result = commandQueue->sendMessage(iter->second.commandQueue, &command);
|
2022-08-15 20:28:16 +02:00
|
|
|
if (result == returnvalue::OK) {
|
2022-02-02 10:29:30 +01:00
|
|
|
++commandsOutstanding;
|
|
|
|
}
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, Mode_t mode,
|
|
|
|
Submode_t submode) {
|
|
|
|
std::map<object_id_t, ChildInfo>::iterator iter;
|
|
|
|
|
|
|
|
for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
|
|
|
|
if (iter->second.commandQueue == queue) {
|
|
|
|
iter->second.mode = mode;
|
|
|
|
iter->second.submode = submode;
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return CHILD_NOT_FOUND;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth) {
|
|
|
|
for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
|
|
|
|
if (iter->second.commandQueue == queue) {
|
|
|
|
iter->second.healthChanged = changedHealth;
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return CHILD_NOT_FOUND;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
MessageQueueId_t SubsystemBase::getCommandQueue() const { return commandQueue->getId(); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-09-29 19:39:37 +02:00
|
|
|
ReturnValue_t SubsystemBase::initialize() { return SystemObject::initialize(); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2018-07-12 16:29:32 +02:00
|
|
|
ReturnValue_t SubsystemBase::performOperation(uint8_t opCode) {
|
2022-02-02 10:29:30 +01:00
|
|
|
childrenChangedMode = false;
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
checkCommandQueue();
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
performChildOperation();
|
2016-06-15 23:48:41 +02:00
|
|
|
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) {
|
2022-02-02 10:29:30 +01:00
|
|
|
switch (message->getCommand()) {
|
|
|
|
case ModeMessage::REPLY_MODE_INFO:
|
|
|
|
updateChildMode(message->getSender(), ModeMessage::getMode(message),
|
|
|
|
ModeMessage::getSubmode(message));
|
|
|
|
childrenChangedMode = true;
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
case ModeMessage::REPLY_MODE_REPLY:
|
|
|
|
case ModeMessage::REPLY_WRONG_MODE_REPLY:
|
|
|
|
updateChildMode(message->getSender(), ModeMessage::getMode(message),
|
|
|
|
ModeMessage::getSubmode(message));
|
|
|
|
childrenChangedMode = true;
|
|
|
|
commandsOutstanding--;
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
case ModeMessage::REPLY_CANT_REACH_MODE:
|
|
|
|
commandsOutstanding--;
|
|
|
|
{
|
|
|
|
for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
|
|
|
|
if (iter->second.commandQueue == message->getSender()) {
|
|
|
|
triggerEvent(MODE_CMD_REJECTED, iter->first, message->getParameter());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
// case ModeMessage::CMD_MODE_COMMAND:
|
|
|
|
// handleCommandedMode(message);
|
2022-08-16 12:12:21 +02:00
|
|
|
// return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
// case ModeMessage::CMD_MODE_ANNOUNCE:
|
|
|
|
// triggerEvent(MODE_INFO, mode, submode);
|
2022-08-16 12:12:21 +02:00
|
|
|
// return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
// case ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY:
|
|
|
|
// triggerEvent(MODE_INFO, mode, submode);
|
|
|
|
// commandAllChildren(message);
|
2022-08-16 12:12:21 +02:00
|
|
|
// return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
default:
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::FAILED;
|
2022-02-02 10:29:30 +01:00
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t SubsystemBase::checkTable(HybridIterator<ModeListEntry> tableIter) {
|
2022-09-29 16:47:23 +02:00
|
|
|
for (; tableIter.value != nullptr; ++tableIter) {
|
2022-02-02 10:29:30 +01:00
|
|
|
if (childrenMap.find(tableIter.value->getObject()) == childrenMap.end()) {
|
2022-09-29 16:47:23 +02:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
using namespace std;
|
|
|
|
sif::warning << "SubsystemBase::checkTable: Could not find Object " << setfill('0') << hex
|
|
|
|
<< "0x" << setw(8) << tableIter.value->getObject() << " in object " << setw(8)
|
2022-09-29 19:39:37 +02:00
|
|
|
<< "0x" << SystemObject::getObjectId() << dec << std::endl;
|
2022-09-29 16:47:23 +02:00
|
|
|
#endif
|
2022-02-02 10:29:30 +01:00
|
|
|
return TABLE_CONTAINS_INVALID_OBJECT_ID;
|
|
|
|
}
|
|
|
|
}
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
void SubsystemBase::replyToCommand(CommandMessage* message) { commandQueue->reply(message); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
|
|
|
void SubsystemBase::setMode(Mode_t newMode, Submode_t newSubmode) {
|
2022-02-02 10:29:30 +01:00
|
|
|
modeHelper.modeChanged(newMode, newSubmode);
|
|
|
|
mode = newMode;
|
|
|
|
submode = newSubmode;
|
|
|
|
modeChanged();
|
|
|
|
announceMode(false);
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
void SubsystemBase::setMode(Mode_t newMode) { setMode(newMode, submode); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
|
|
|
void SubsystemBase::commandAllChildren(CommandMessage* message) {
|
2022-02-02 10:29:30 +01:00
|
|
|
std::map<object_id_t, ChildInfo>::iterator iter;
|
|
|
|
for (iter = childrenMap.begin(); iter != childrenMap.end(); ++iter) {
|
|
|
|
commandQueue->sendMessage(iter->second.commandQueue, message);
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SubsystemBase::getMode(Mode_t* mode, Submode_t* submode) {
|
2022-02-02 10:29:30 +01:00
|
|
|
*mode = this->mode;
|
|
|
|
*submode = this->submode;
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
void SubsystemBase::setToExternalControl() { healthHelper.setHealth(EXTERNAL_CONTROL); }
|
2016-06-15 23:48:41 +02:00
|
|
|
|
|
|
|
void SubsystemBase::announceMode(bool recursive) {
|
2022-02-02 10:29:30 +01:00
|
|
|
triggerEvent(MODE_INFO, mode, submode);
|
|
|
|
if (recursive) {
|
|
|
|
CommandMessage command;
|
|
|
|
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_ANNOUNCE_RECURSIVELY, 0, 0);
|
|
|
|
commandAllChildren(&command);
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void SubsystemBase::checkCommandQueue() {
|
2022-02-02 10:29:30 +01:00
|
|
|
ReturnValue_t result;
|
|
|
|
CommandMessage command;
|
|
|
|
|
2022-08-15 20:28:16 +02:00
|
|
|
for (result = commandQueue->receiveMessage(&command); result == returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
result = commandQueue->receiveMessage(&command)) {
|
|
|
|
result = healthHelper.handleHealthCommand(&command);
|
2022-08-15 20:28:16 +02:00
|
|
|
if (result == returnvalue::OK) {
|
2022-02-02 10:29:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = modeHelper.handleModeCommand(&command);
|
2022-08-15 20:28:16 +02:00
|
|
|
if (result == returnvalue::OK) {
|
2022-02-02 10:29:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = handleModeReply(&command);
|
2022-08-15 20:28:16 +02:00
|
|
|
if (result == returnvalue::OK) {
|
2022-02-02 10:29:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = handleCommandMessage(&command);
|
2022-08-15 20:28:16 +02:00
|
|
|
if (result != returnvalue::OK) {
|
2022-02-02 10:29:30 +01:00
|
|
|
CommandMessage reply;
|
|
|
|
reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, command.getCommand());
|
|
|
|
replyToCommand(&reply);
|
|
|
|
}
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReturnValue_t SubsystemBase::setHealth(HealthState health) {
|
2022-02-02 10:29:30 +01:00
|
|
|
switch (health) {
|
|
|
|
case HEALTHY:
|
|
|
|
case EXTERNAL_CONTROL:
|
|
|
|
healthHelper.setHealth(health);
|
2022-08-15 20:28:16 +02:00
|
|
|
return returnvalue::OK;
|
2022-02-02 10:29:30 +01:00
|
|
|
default:
|
|
|
|
return INVALID_HEALTH_STATE;
|
|
|
|
}
|
2016-06-15 23:48:41 +02:00
|
|
|
}
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
HasHealthIF::HealthState SubsystemBase::getHealth() { return healthHelper.getHealth(); }
|
2018-07-12 16:29:32 +02:00
|
|
|
|
2022-09-29 19:39:37 +02:00
|
|
|
ReturnValue_t SubsystemBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
|
|
|
return modetree::connectModeTreeParent(parent, *this, healthHelper, modeHelper);
|
|
|
|
}
|
|
|
|
|
|
|
|
object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectId(); }
|
|
|
|
|
2022-02-02 10:29:30 +01:00
|
|
|
void SubsystemBase::modeChanged() {}
|
2022-09-29 19:21:24 +02:00
|
|
|
|
|
|
|
ReturnValue_t SubsystemBase::registerChild(const ModeTreeChildIF& child) {
|
|
|
|
ChildInfo info;
|
|
|
|
|
|
|
|
const HasModesIF& modeChild = child.getModeIF();
|
|
|
|
// intentional to force an initial command during system startup
|
|
|
|
info.commandQueue = modeChild.getCommandQueue();
|
|
|
|
info.mode = HasModesIF::MODE_UNDEFINED;
|
|
|
|
info.submode = SUBMODE_NONE;
|
|
|
|
info.healthChanged = false;
|
|
|
|
|
|
|
|
auto resultPair = childrenMap.emplace(child.getObjectId(), info);
|
|
|
|
if (not resultPair.second) {
|
|
|
|
return COULD_NOT_INSERT_CHILD;
|
|
|
|
}
|
|
|
|
return returnvalue::OK;
|
|
|
|
}
|
2022-09-29 19:39:37 +02:00
|
|
|
|
|
|
|
const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; }
|
|
|
|
|
|
|
|
const HasModesIF& SubsystemBase::getModeIF() const { return *this; }
|