Compare commits
65 Commits
develop_up
...
mohr_intro
Author | SHA1 | Date | |
---|---|---|---|
7ebfcdda60 | |||
5c25a2777c | |||
7f80e91a91 | |||
732419e239 | |||
d328f3e190 | |||
4c0d9ae039 | |||
753d587b69 | |||
979a7b7d75 | |||
a30146a799 | |||
ae2823ba2d | |||
3a433915f1 | |||
d766469f1e | |||
33a2fb48e5 | |||
531d8c45e8 | |||
14a7dd885b | |||
50a4ec97ef | |||
de93bff561 | |||
ad4adc7cba | |||
6a76857f5f | |||
2044e1cde2 | |||
b56b54951b | |||
1fc50a1562 | |||
e831ba11d2 | |||
0da490481e | |||
146c3471d0 | |||
1816c3f623 | |||
d03d5aa74c | |||
26e97ddf89 | |||
be3a57a795 | |||
318a933b3b | |||
13b97abf0d | |||
e8480cf962 | |||
a5e6107001 | |||
f95c373076 | |||
e03731bcf8 | |||
9fe8579377 | |||
2714e588d7 | |||
e905288adc | |||
3805ea50a7 | |||
699bd694cd | |||
c35a0a8541 | |||
e0a072859b | |||
067cb7d0f8 | |||
2c17af4ef8 | |||
110fb43b9c | |||
1c527c4946 | |||
4c0f67adf5 | |||
450ad1dad4 | |||
1dfb3323f7 | |||
f5adcd0625 | |||
bc593c938d | |||
3f8f17a66e | |||
3260a03544 | |||
3ffdc0d31f | |||
d367baa42c | |||
59f8dd1322 | |||
61b4e68f3d | |||
e34664d265 | |||
20eb232bf5 | |||
dd281f8a67 | |||
f9e9ff320f | |||
f56646d2c3 | |||
ef18377cef | |||
0c057c66b1 | |||
34c50ce3e2 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,5 +10,8 @@
|
||||
.settings
|
||||
.metadata
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
/build*
|
||||
/cmake-build*
|
||||
|
8
.idea/cmake.xml
generated
8
.idea/cmake.xml
generated
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeSharedSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host" />
|
||||
</configurations>
|
||||
</component>
|
||||
</project>
|
16
CHANGELOG.md
16
CHANGELOG.md
@ -10,8 +10,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Fixes
|
||||
|
||||
- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source
|
||||
data with a size limited only by the size of `size_t`.
|
||||
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
|
||||
number fields stored the actual length of the field instead of the length minus 1 like specified
|
||||
in the CFDP standard.
|
||||
@ -27,11 +25,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
- add CFDP subsystem ID
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||
- `PusTmZcWriter` now exposes API to set message counter field.
|
||||
|
||||
## Changed
|
||||
|
||||
- HK generation is now countdown based.
|
||||
- Bump ETL version to 20.35.14
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
|
||||
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
|
||||
@ -40,7 +35,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Assert that `FixedArrayList` is larger than 0 at compile time.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
|
||||
- Health functions are virtual now.
|
||||
|
||||
## Added
|
||||
|
||||
- `EventManager`: Add function to print all listeners.
|
||||
|
||||
## Changed
|
||||
|
||||
- `EventManager`: Queue depth is configurable now
|
||||
|
||||
# [v6.0.0] 2023-02-10
|
||||
|
||||
@ -116,8 +118,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Added
|
||||
|
||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
|
||||
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
|
||||
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
||||
|
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
set(FSFW_ETL_LIB_VERSION
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.35.14
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.36.0
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
@ -80,7 +80,7 @@ set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
||||
3
|
||||
CACHE STRING "Catch2 library major version requirement")
|
||||
set(FSFW_CATCH2_LIB_VERSION
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
|
||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.3.2
|
||||
CACHE STRING "Catch2 library exact version requirement")
|
||||
|
||||
# Keep this off by default for now. See PR:
|
||||
|
4
automation/Jenkinsfile
vendored
4
automation/Jenkinsfile
vendored
@ -97,7 +97,7 @@ pipeline {
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
|
||||
}
|
||||
@ -116,7 +116,7 @@ pipeline {
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
||||
}
|
||||
|
@ -51,10 +51,7 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_theme_options = {
|
||||
"extra_nav_links": {
|
||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
||||
}
|
||||
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,4 +8,4 @@ if(FSFW_ADD_HAL)
|
||||
add_subdirectory(fsfw_hal)
|
||||
endif()
|
||||
|
||||
add_subdirectory(fsfw_tests)
|
||||
#add_subdirectory(fsfw_tests)
|
||||
|
@ -7,7 +7,7 @@ add_subdirectory(cfdp)
|
||||
add_subdirectory(container)
|
||||
add_subdirectory(controller)
|
||||
add_subdirectory(datapool)
|
||||
add_subdirectory(datapoollocal)
|
||||
#add_subdirectory(datapoollocal)
|
||||
add_subdirectory(devicehandlers)
|
||||
add_subdirectory(events)
|
||||
add_subdirectory(fdir)
|
||||
@ -15,20 +15,22 @@ add_subdirectory(globalfunctions)
|
||||
add_subdirectory(health)
|
||||
add_subdirectory(housekeeping)
|
||||
add_subdirectory(internalerror)
|
||||
add_subdirectory(introspection)
|
||||
add_subdirectory(ipc)
|
||||
add_subdirectory(memory)
|
||||
add_subdirectory(modes)
|
||||
add_subdirectory(objectmanager)
|
||||
add_subdirectory(parameters)
|
||||
add_subdirectory(power)
|
||||
#add_subdirectory(power)
|
||||
add_subdirectory(serialize)
|
||||
add_subdirectory(serviceinterface)
|
||||
add_subdirectory(storagemanager)
|
||||
add_subdirectory(subsystem)
|
||||
add_subdirectory(tasks)
|
||||
add_subdirectory(tcdistribution)
|
||||
add_subdirectory(thermal)
|
||||
#add_subdirectory(thermal)
|
||||
add_subdirectory(timemanager)
|
||||
add_subdirectory(tmtc)
|
||||
add_subdirectory(tmtcpacket)
|
||||
add_subdirectory(tmtcservices)
|
||||
add_subdirectory(filesystem)
|
||||
@ -36,7 +38,7 @@ add_subdirectory(filesystem)
|
||||
# Optional
|
||||
|
||||
if(FSFW_ADD_MONITORING)
|
||||
add_subdirectory(monitoring)
|
||||
#add_subdirectory(monitoring)
|
||||
endif()
|
||||
if(FSFW_ADD_PUS)
|
||||
add_subdirectory(pus)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef FSFW_INC_FSFW_ACTION_H_
|
||||
#define FSFW_INC_FSFW_ACTION_H_
|
||||
|
||||
#include "fsfw/action/Action.h"
|
||||
#include "fsfw/action/ActionHelper.h"
|
||||
#include "fsfw/action/ActionMessage.h"
|
||||
#include "fsfw/action/CommandActionHelper.h"
|
||||
|
70
src/fsfw/action/Action.cpp
Normal file
70
src/fsfw/action/Action.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "Action.h"
|
||||
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
|
||||
#undef Action
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
|
||||
Action::Action() {}
|
||||
|
||||
void Action::setEnum(EnumIF *theEnum) {
|
||||
id = theEnum->getValue();
|
||||
name = theEnum->getDescription();
|
||||
}
|
||||
|
||||
const char *Action::getName() { return name; }
|
||||
#else
|
||||
Action::Action(ActionId_t id) : id(id) {}
|
||||
#endif
|
||||
ActionId_t Action::getId() { return id; }
|
||||
|
||||
void Action::clear() {
|
||||
tc = store_address_t();
|
||||
tcOffset = 0;
|
||||
commandedBy = MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
|
||||
void Action::registerParameter(ParameterIF *parameter) { parameterList.push_back(parameter); }
|
||||
|
||||
std::vector<ParameterIF *> const *Action::getParameters() const { return ¶meterList; }
|
||||
|
||||
size_t Action::getSerializedSize() const {
|
||||
size_t size = SerializeAdapter::getSerializedSize(&id);
|
||||
for (auto parameter : *getParameters()) {
|
||||
size += parameter->getSerializedSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t Action::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
for (auto parameter : *getParameters()) {
|
||||
result = parameter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t Action::deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) {
|
||||
ReturnValue_t result = returnvalue::OK;/* TODO not needed as must have been read before to find this
|
||||
action = SerializeAdapter::deSerialize(&id, buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}*/
|
||||
for (auto parameter : *getParameters()) {
|
||||
result = parameter->deSerialize(buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
64
src/fsfw/action/Action.h
Normal file
64
src/fsfw/action/Action.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/introspection/HasTmTcParametersIF.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ActionMessage.h"
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
#include "../introspection/Enum.h"
|
||||
#endif
|
||||
|
||||
// TODO ActionId_t
|
||||
|
||||
class Action : public SerializeIF, public HasTmTcParametersIF {
|
||||
public:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
Action();
|
||||
void setEnum(EnumIF *id);
|
||||
const char *getName();
|
||||
#else
|
||||
Action(ActionId_t id);
|
||||
#endif
|
||||
|
||||
store_address_t getTc();
|
||||
size_t getTcOffset();
|
||||
|
||||
// if an action is triggered by a TC, this should be set to be able to handle replies
|
||||
// TODO make deleting it safe
|
||||
// TODO integrate with internal commands
|
||||
store_address_t tc;
|
||||
size_t tcOffset;
|
||||
MessageQueueId_t commandedBy;
|
||||
|
||||
ActionId_t getId();
|
||||
|
||||
|
||||
|
||||
void clear();
|
||||
|
||||
[[nodiscard]] virtual ReturnValue_t handle() = 0;
|
||||
|
||||
void registerParameter(ParameterIF *parameter) override;
|
||||
|
||||
std::vector<ParameterIF *> const *getParameters() const override;
|
||||
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
size_t getSerializedSize() const override;
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
ActionId_t id;
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
const char *name;
|
||||
#endif
|
||||
std::vector<ParameterIF *> parameterList;
|
||||
};
|
@ -1,3 +1,6 @@
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
#include <fsfw/tmtc/TmMessage.h>
|
||||
|
||||
#include "fsfw/action.h"
|
||||
#include "fsfw/ipc/MessageQueueSenderIF.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
@ -10,8 +13,8 @@ ActionHelper::~ActionHelper() = default;
|
||||
|
||||
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
|
||||
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
|
||||
ActionId_t currentAction = ActionMessage::getActionId(command);
|
||||
prepareExecution(command->getSender(), currentAction, ActionMessage::getStoreId(command));
|
||||
prepareExecution(command->getSender(), ActionMessage::getOffset(command),
|
||||
ActionMessage::getStoreId(command));
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
return CommandMessage::UNKNOWN_COMMAND;
|
||||
@ -23,6 +26,12 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
if (ipcStore == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
tmManager = ObjectManager::instance()->get<TmManager>(objects::TM_MANAGER);
|
||||
if (tmManager == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (queueToUse_ != nullptr) {
|
||||
setQueueToUse(queueToUse_);
|
||||
}
|
||||
@ -57,35 +66,89 @@ void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t co
|
||||
|
||||
void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
MessageQueueIF const* ActionHelper::getQueue() const { return queueToUse; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
|
||||
store_address_t dataAddress) {
|
||||
bool hasAdditionalData = false;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result;
|
||||
if (dataAddress != store_address_t::invalid()) {
|
||||
hasAdditionalData = true;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
const uint8_t* tcData = nullptr;
|
||||
size_t tcDataSize = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &tcData, &tcDataSize);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||
if (hasAdditionalData) {
|
||||
|
||||
FsfwProtocolHeader header;
|
||||
|
||||
const uint8_t* dataPtr = tcData + offset;
|
||||
size_t size = tcDataSize - offset;
|
||||
|
||||
result = header.deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
|
||||
|
||||
if (header.getInterface() != HasActionsIF::INTERFACE_ID or
|
||||
header.getFunction() != HasActionsIF::Functions::EXECUTE_ACTION) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
ActionId_t actionId;
|
||||
|
||||
result =
|
||||
SerializeAdapter::deSerialize(&actionId, &dataPtr, &size, SerializeIF::Endianness::NETWORK);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
auto actionIter = actionMap.find(actionId);
|
||||
if (actionIter == actionMap.end()) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_ACTION_ID);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
Action* action = actionIter->second;
|
||||
|
||||
result = action->deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
|
||||
if ((result != returnvalue::OK) || (size != 0)) { // TODO write unittest for second condition
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_PARAMETERS);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
// TODO call action->check()
|
||||
action->commandedBy = commandedBy;
|
||||
result = owner->executeAction(action);
|
||||
|
||||
// TODO safetify dynamic cast
|
||||
result = tmManager->sendTmPacket(dynamic_cast<SystemObjectIF*>(owner)->getObjectId(), HasActionsIF::INTERFACE_ID,
|
||||
HasActionsIF::Functions::EXECUTION_IN_PROGRESS, action,
|
||||
dataAddress, offset);
|
||||
if (result != returnvalue::OK) {
|
||||
sif::error << "replying action failed " << std::hex << result << std::dec << std::endl;
|
||||
}
|
||||
|
||||
// ipcStore->deleteData(dataAddress);
|
||||
if (result == HasActionsIF::EXECUTION_FINISHED) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
// queueToUse->sendMessage(commandedBy, &reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -170,3 +233,11 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ActionId_t rep
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ActionHelper::registerAction(Action* action) {
|
||||
// TODO error handling
|
||||
ActionId_t id = action->getId();
|
||||
actionMap.emplace(id, action);
|
||||
}
|
||||
|
||||
std::map<ActionId_t, Action*> const* ActionHelper::getActionMap() { return &actionMap; }
|
@ -1,9 +1,12 @@
|
||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
||||
|
||||
#include <fsfw/tmtc/TmManager.h>
|
||||
|
||||
#include "ActionMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief Action Helper is a helper class which handles action messages
|
||||
*
|
||||
@ -98,6 +101,16 @@ class ActionHelper {
|
||||
*/
|
||||
void setQueueToUse(MessageQueueIF* queue);
|
||||
|
||||
/**
|
||||
* Needed so templateAction can check if actionHelper was
|
||||
* contructed already to aid in debuggig a nasty coding error.
|
||||
*/
|
||||
MessageQueueIF const* getQueue() const;
|
||||
|
||||
void registerAction(Action* action);
|
||||
|
||||
std::map<ActionId_t, Action*> const* getActionMap();
|
||||
|
||||
protected:
|
||||
//! Increase of value of this per step
|
||||
static const uint8_t STEP_OFFSET = 1;
|
||||
@ -106,8 +119,11 @@ class ActionHelper {
|
||||
//! Queue to be used as response sender, has to be set in ctor or with
|
||||
//! setQueueToUse
|
||||
MessageQueueIF* queueToUse;
|
||||
TmManager* tmManager = nullptr;
|
||||
//! Pointer to an IPC Store, initialized during construction or
|
||||
StorageManagerIF* ipcStore = nullptr;
|
||||
//! Map of all implemented Actions
|
||||
std::map<ActionId_t, Action*> actionMap;
|
||||
|
||||
/**
|
||||
* Internal function called by handleActionMessage
|
||||
@ -115,7 +131,7 @@ class ActionHelper {
|
||||
* @param actionId ID of action to be done
|
||||
* @param dataAddress Address of additional data in IPC Store
|
||||
*/
|
||||
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
virtual void prepareExecution(MessageQueueId_t commandedBy, size_t offset,
|
||||
store_address_t dataAddress);
|
||||
/**
|
||||
* @brief Default implementation is empty.
|
||||
|
@ -6,14 +6,14 @@ ActionMessage::ActionMessage() = default;
|
||||
|
||||
ActionMessage::~ActionMessage() = default;
|
||||
|
||||
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
|
||||
void ActionMessage::setCommand(CommandMessage* message, size_t offset,
|
||||
store_address_t parameters) {
|
||||
message->setCommand(EXECUTE_ACTION);
|
||||
message->setParameter(fid);
|
||||
message->setParameter(offset);
|
||||
message->setParameter2(parameters.raw);
|
||||
}
|
||||
|
||||
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
|
||||
size_t ActionMessage::getOffset(const CommandMessage* message) {
|
||||
return ActionId_t(message->getParameter());
|
||||
}
|
||||
|
||||
|
@ -27,9 +27,9 @@ class ActionMessage {
|
||||
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
|
||||
|
||||
virtual ~ActionMessage();
|
||||
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters);
|
||||
static void setCommand(CommandMessage* message, size_t offset, store_address_t parameters);
|
||||
|
||||
static ActionId_t getActionId(const CommandMessage* message);
|
||||
static size_t getOffset(const CommandMessage* message);
|
||||
static store_address_t getStoreId(const CommandMessage* message);
|
||||
|
||||
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
|
||||
|
@ -1,3 +1,3 @@
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp
|
||||
${LIB_FSFW_NAME} PRIVATE Action.cpp ActionHelper.cpp ActionMessage.cpp
|
||||
CommandActionHelper.cpp SimpleActionHelper.cpp)
|
||||
|
@ -74,24 +74,24 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
|
||||
switch (reply->getCommand()) {
|
||||
case ActionMessage::COMPLETION_SUCCESS:
|
||||
commandCount--;
|
||||
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
|
||||
// owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); TODO
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::COMPLETION_FAILED:
|
||||
commandCount--;
|
||||
owner->completionFailedReceived(ActionMessage::getActionId(reply),
|
||||
ActionMessage::getReturnCode(reply));
|
||||
// owner->completionFailedReceived(ActionMessage::getActionId(reply),
|
||||
// ActionMessage::getReturnCode(reply));
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::STEP_SUCCESS:
|
||||
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
|
||||
ActionMessage::getStep(reply));
|
||||
// owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
|
||||
// ActionMessage::getStep(reply));
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::STEP_FAILED:
|
||||
commandCount--;
|
||||
owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
|
||||
ActionMessage::getReturnCode(reply));
|
||||
// owner->stepFailedReceived(ActionMessage::getActionId(reply), ActionMessage::getStep(reply),
|
||||
// ActionMessage::getReturnCode(reply));
|
||||
return returnvalue::OK;
|
||||
case ActionMessage::DATA_REPLY:
|
||||
extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
|
||||
// extractDataForOwner(ActionMessage::getActionId(reply), ActionMessage::getStoreId(reply));
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return returnvalue::FAILED;
|
||||
|
@ -16,8 +16,8 @@ class CommandActionHelper {
|
||||
public:
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
|
@ -1,11 +1,13 @@
|
||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||
#define FSFW_ACTION_HASACTIONSIF_H_
|
||||
|
||||
#include "Action.h"
|
||||
#include "ActionHelper.h"
|
||||
#include "ActionMessage.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include <fsfw/tmtc/FsfwProtocolHeader.h>
|
||||
|
||||
/**
|
||||
* @brief
|
||||
@ -40,12 +42,18 @@ class HasActionsIF {
|
||||
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
|
||||
|
||||
enum Functions : FsfwProtocolHeader::FunctionType_t { EXECUTE_ACTION, EXECUTION_IN_PROGRESS };
|
||||
|
||||
virtual ~HasActionsIF() = default;
|
||||
/**
|
||||
* Function to get the MessageQueueId_t of the implementing object
|
||||
* @return MessageQueueId_t of the object
|
||||
*
|
||||
*/
|
||||
[[nodiscard]] virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
||||
virtual ActionHelper* getActionHelper() = 0;
|
||||
/**
|
||||
* Execute or initialize the execution of a certain function.
|
||||
* The ActionHelpers will execute this function and behave differently
|
||||
@ -55,8 +63,7 @@ class HasActionsIF {
|
||||
* -@c EXECUTION_FINISHED Finish reply will be generated
|
||||
* -@c Not returnvalue::OK Step failure reply will be generated
|
||||
*/
|
||||
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) = 0;
|
||||
virtual ReturnValue_t executeAction(Action* action) = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_ACTION_HASACTIONSIF_H_ */
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "fsfw/action.h"
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
|
||||
|
||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
|
||||
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
|
||||
@ -30,25 +32,57 @@ void SimpleActionHelper::resetHelper() {
|
||||
lastCommander = 0;
|
||||
}
|
||||
|
||||
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
|
||||
store_address_t dataAddress) {
|
||||
CommandMessage reply;
|
||||
if (isExecuting) {
|
||||
ipcStore->deleteData(dataAddress);
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::IS_BUSY);
|
||||
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, HasActionsIF::IS_BUSY);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != returnvalue::OK) {
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
lastCommander = commandedBy;
|
||||
lastAction = actionId;
|
||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||
|
||||
|
||||
dataPtr += offset;
|
||||
size -=offset;
|
||||
|
||||
ActionId_t actionId;
|
||||
|
||||
result = SerializeAdapter::deSerialize(&actionId, &dataPtr, &size, SerializeIF::Endianness::NETWORK);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
auto actionIter = actionMap.find(actionId);
|
||||
if (actionIter == actionMap.end()){
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_ACTION_ID);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
Action* action = actionIter->second;
|
||||
result = action->deSerialize(&dataPtr, &size, SerializeIF::Endianness::NETWORK);
|
||||
if ((result != returnvalue::OK) or (size != 0)) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, HasActionsIF::INVALID_PARAMETERS);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
return;
|
||||
}
|
||||
result = action->handle();
|
||||
ipcStore->deleteData(dataAddress);
|
||||
switch (result) {
|
||||
case returnvalue::OK:
|
||||
|
@ -17,7 +17,7 @@ class SimpleActionHelper : public ActionHelper {
|
||||
ReturnValue_t reportData(SerializeIF* data);
|
||||
|
||||
protected:
|
||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
virtual void prepareExecution(MessageQueueId_t commandedBy, size_t offset,
|
||||
store_address_t dataAddress) override;
|
||||
void resetHelper() override;
|
||||
|
||||
|
29
src/fsfw/action/TemplateAction.h
Normal file
29
src/fsfw/action/TemplateAction.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "Action.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
template <class owner_class, class action_type, class ActionEnum>
|
||||
class TemplateAction : public Action {
|
||||
public:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
TemplateAction(owner_class *myOwner, ActionEnum id) : Action(), myOwner(myOwner) {
|
||||
Action::setEnum(&id);
|
||||
if (myOwner->getActionHelper() == nullptr) {
|
||||
sif::error
|
||||
<< "TemplateAction::TemplateAction: Action instances need to be created (ie located) after the actionHelper instance."
|
||||
<< "Program will segfault now..." << std::endl;
|
||||
}
|
||||
myOwner->getActionHelper()->registerAction(this);
|
||||
}
|
||||
#else
|
||||
TemplateAction(owner_class *myOwner, ActionEnum id) : Action((uint32_t)id), myOwner(myOwner) {
|
||||
myOwner->getActionHelper()->registerAction(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
ReturnValue_t handle() override { return myOwner->handleAction(dynamic_cast<action_type *>(this)); }
|
||||
|
||||
private:
|
||||
owner_class *myOwner;
|
||||
};
|
@ -2,9 +2,7 @@
|
||||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
#include "cfdp/tlv/Lv.h"
|
||||
#include "cfdp/tlv/StringLv.h"
|
||||
#include "cfdp/tlv/Tlv.h"
|
||||
|
@ -51,8 +51,9 @@ class VarLenField : public SerializeIF {
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
|
||||
// compiler
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
@ -1,2 +1 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||
|
@ -1,546 +0,0 @@
|
||||
#include "DestHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
||||
: tlvVec(params.maxTlvsInOnePdu),
|
||||
userTlvVec(params.maxTlvsInOnePdu),
|
||||
dp(std::move(params)),
|
||||
fp(fsfwParams),
|
||||
tp(params.maxFilenameLen) {
|
||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::METADATA) {
|
||||
result = handleMetadataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
// To decrease the already high complexity of the software, all packets arriving before
|
||||
// a metadata PDU are deleted.
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
fp.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
dp.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DATA) {
|
||||
result = handleFileDataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
||||
// TODO: Support for check timer missing
|
||||
result = handleEofPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
||||
result = handleTransferCompletion();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
||||
result = sendFinishedPdu();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
finish();
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
// TODO: Will be implemented at a later stage
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (dp.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
dp.packetListRef.push_back(packet);
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
if (fp.tmStore == nullptr) {
|
||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fp.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.tcStore == nullptr) {
|
||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fp.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
metadataInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
// TODO: The standard does not really specify what happens if this kind of error happens
|
||||
// I think it might be a good idea to cache some sort of error code, which
|
||||
// is translated into a warning and/or event by an upper layer
|
||||
if (result != OK) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader, metadataInfo);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::FileSize offset;
|
||||
FileDataInfo fdInfo(offset);
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t fileSegmentLen = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = offset.value();
|
||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
segParams.offset = offset.value();
|
||||
segParams.id = tp.transactionId;
|
||||
segParams.length = fileSegmentLen;
|
||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
||||
size_t segmentMetadatLen = 0;
|
||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
||||
dp.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
||||
<< result << std::endl;
|
||||
#endif
|
||||
tp.vfsErrorCount++;
|
||||
if (tp.vfsErrorCount < 3) {
|
||||
// TODO: Provide execution step as parameter
|
||||
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
|
||||
result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
tp.vfsErrorCount = 0;
|
||||
}
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
// Process EOF PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
EofInfo eofInfo(nullptr);
|
||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
tp.crc = eofInfo.getChecksum();
|
||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
||||
if (fileSizeFromEof > tp.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
dp.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
const uint8_t* rawData, size_t maxSize) {
|
||||
// TODO: try to extract destination ID for error
|
||||
// TODO: Invalid metadata PDU.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
||||
#else
|
||||
#endif
|
||||
PduHeaderReader headerReader(rawData, maxSize);
|
||||
result = headerReader.parseData();
|
||||
if (result != OK) {
|
||||
// TODO: Now this really should not happen. Warning or error,
|
||||
// yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Header failed" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
return result;
|
||||
}
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
||||
// covered by the standard.
|
||||
// Warning or error, yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
}
|
||||
// TODO: Appropriate returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
||||
if (fsmRes.state != CfdpStates::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
size_t sourceNameSize = 0;
|
||||
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize + 1 > tp.sourceName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize + 1 > tp.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// handling to allow only specifying target directory. Example:
|
||||
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
||||
if (dp.user.vfs.isDirectory(tp.destName.data())) {
|
||||
result = tryBuildingAbsoluteDestName(destNameSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
result = dp.user.vfs.truncateFile(fparams);
|
||||
if (result != returnvalue::OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
}
|
||||
}
|
||||
EntityId sourceId;
|
||||
reader.getSourceId(sourceId);
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
|
||||
// TODO: Warning, event etc.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler" << __func__
|
||||
<< ": No remote configuration found for destination ID "
|
||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||
params.fileSize = tp.fileSize.getSize();
|
||||
params.destFileName = tp.destName.data();
|
||||
params.sourceFileName = tp.sourceName.data();
|
||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
||||
params.msgsToUserLen = info.getOptionsLen();
|
||||
dp.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (tp.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
||||
char baseNameBuf[tp.destName.size()]{};
|
||||
FilesystemParams fparamsSrc(tp.sourceName.data());
|
||||
size_t baseNameLen = 0;
|
||||
ReturnValue_t result =
|
||||
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
|
||||
if (result != returnvalue::OK or baseNameLen == 0) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
|
||||
return FAILED;
|
||||
}
|
||||
// Destination name + slash + base name + null termination
|
||||
if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
||||
"dest filename too large after adding source base name");
|
||||
return FAILED;
|
||||
}
|
||||
tp.destName[destNameSize++] = '/';
|
||||
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
||||
destNameSize += baseNameLen;
|
||||
tp.destName[destNameSize++] = '\0';
|
||||
return OK;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
|
||||
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
|
||||
static_cast<uint8_t>(fsmRes.step), result);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::finish() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
fsmRes.state = CfdpStates::IDLE;
|
||||
fsmRes.step = TransactionStep::IDLE;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
// TODO: Checksum verification and notice of completion
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
||||
while (currentOffset < tp.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
||||
readLen = tp.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
||||
// a warning or trigger an event because this should generally not happen
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
if (value == tp.crc) {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
} else {
|
||||
// TODO: Proper error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
||||
#endif
|
||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
||||
tp.deliveryStatus);
|
||||
dp.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage msg(storeId);
|
||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
fsmRes.packetsSent++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
||||
return fsmRes.step;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
||||
fsmRes.errors = errors;
|
||||
fsmRes.result = OK;
|
||||
if (fsmRes.errors > 0) {
|
||||
fsmRes.result = FAILED;
|
||||
}
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
fsmRes.errorCodes[errorIdx] = result;
|
||||
errorIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fp.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
@ -1,206 +0,0 @@
|
||||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
|
||||
#include <etl/list.h>
|
||||
#include <etl/set.h>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "RemoteConfigTableIF.h"
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
struct DestHandlerParams {
|
||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
||||
PacketInfoListBase& packetList,
|
||||
// TODO: This container can potentially take tons of space. For a better
|
||||
// memory efficient implementation, an additional abstraction could be
|
||||
// be used so users can use uint32_t as the pair type
|
||||
LostSegmentsListBase& lostSegmentsContainer)
|
||||
: cfg(std::move(cfg)),
|
||||
user(user),
|
||||
remoteCfgTable(remoteCfgTable),
|
||||
packetListRef(packetList),
|
||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
RemoteConfigTableIF& remoteCfgTable;
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 10;
|
||||
size_t maxFilenameLen = 255;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
||||
StorageManagerIF& tmStore)
|
||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
||||
this->tcStore = &tcStore;
|
||||
this->tmStore = &tmStore;
|
||||
}
|
||||
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter)
|
||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
MessageQueueIF* msgQueue;
|
||||
EventReportingProxyIF* eventReporter = nullptr;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
};
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
SENDING_ACK_PDU = 3,
|
||||
TRANSFER_COMPLETION = 4,
|
||||
SENDING_FINISHED_PDU = 5
|
||||
};
|
||||
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpStates state = CfdpStates::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
void resetOfIteration() {
|
||||
result = returnvalue::OK;
|
||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
packetsSent = 0;
|
||||
errors = 0;
|
||||
errorCodes.fill(returnvalue::OK);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Will be returned if it is advisable to call the state machine operation call again
|
||||
*/
|
||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& performStateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
ReturnValue_t passPacket(PacketInfo packet);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
// Initialize char vectors with length + 1 for 0 termination
|
||||
explicit TransactionParams(size_t maxFileNameLen)
|
||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
||||
|
||||
void reset() {
|
||||
pduConf = PduConfig();
|
||||
transactionId = TransactionId();
|
||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
||||
std::fill(destName.begin(), destName.end(), '\0');
|
||||
fileSize.setFileSize(0, false);
|
||||
conditionCode = ConditionCode::NO_ERROR;
|
||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
closureRequested = false;
|
||||
vfsErrorCount = 0;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
uint16_t vfsErrorCount = 0;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
uint32_t crc = 0;
|
||||
uint64_t progress = 0;
|
||||
RemoteEntityCfg* remoteCfg = nullptr;
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<cfdp::Tlv> userTlvVec;
|
||||
DestHandlerParams dp;
|
||||
FsfwParams fp;
|
||||
TransactionParams tp;
|
||||
FsmResult fsmRes;
|
||||
|
||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
||||
size_t maxSize);
|
||||
ReturnValue_t handleTransferCompletion();
|
||||
ReturnValue_t tryBuildingAbsoluteDestName(size_t destNameSize);
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
@ -1 +0,0 @@
|
||||
#include "SourceHandler.h"
|
@ -1,6 +0,0 @@
|
||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
class SourceHandler {};
|
||||
|
||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
@ -5,18 +5,5 @@ namespace cfdp {
|
||||
|
||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
|
||||
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
|
||||
|
||||
namespace events {
|
||||
|
||||
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
|
||||
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
||||
|
||||
} // namespace events
|
||||
|
||||
} // namespace cfdp
|
||||
}
|
||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
@ -23,6 +23,8 @@ class EntityIdTlv : public TlvIF {
|
||||
*/
|
||||
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
||||
|
||||
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||
// the compiler
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
@ -26,6 +26,8 @@ class FilestoreRequestTlv : public cfdp::FilestoreTlvBase {
|
||||
*/
|
||||
ReturnValue_t deSerialize(cfdp::Tlv &tlv, Endianness endianness);
|
||||
|
||||
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
|
||||
// compiler
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
@ -29,6 +29,8 @@ class FilestoreResponseTlv : public cfdp::FilestoreTlvBase {
|
||||
*/
|
||||
ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness);
|
||||
|
||||
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||
// the compiler
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
|
@ -155,8 +155,8 @@ class FixedMap : public SerializeIF {
|
||||
|
||||
uint32_t maxSize() const { return theMap.maxSize(); }
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
ReturnValue_t result =
|
||||
SerializeAdapter::serialize(&this->_size, buffer, size, maxSize, streamEndianness);
|
||||
uint32_t i = 0;
|
||||
@ -170,7 +170,7 @@ class FixedMap : public SerializeIF {
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual size_t getSerializedSize() const {
|
||||
size_t getSerializedSize() const override {
|
||||
uint32_t printSize = sizeof(_size);
|
||||
uint32_t i = 0;
|
||||
|
||||
@ -182,8 +182,8 @@ class FixedMap : public SerializeIF {
|
||||
return printSize;
|
||||
}
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override {
|
||||
ReturnValue_t result =
|
||||
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
|
||||
if (this->_size > theMap.maxSize()) {
|
||||
|
@ -1,2 +1 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp
|
||||
ExtendedControllerBase.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp)
|
||||
|
@ -4,31 +4,66 @@
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, size_t commandQueueDepth)
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
parentId(parentId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
healthHelper(this, setObjectId),
|
||||
actionHelper(this, commandQueue),
|
||||
datapoolHelper(this),
|
||||
housekeepingHelper(this) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||
}
|
||||
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t ControllerBase::initialize() {
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = healthHelper.initialize();
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return SystemObject::initialize();
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = actionHelper.initialize(commandQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = housekeepingHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = datapoolHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
@ -47,6 +82,12 @@ void ControllerBase::handleQueue() {
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = actionHelper.handleActionMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = handleCommandMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
continue;
|
||||
@ -58,7 +99,7 @@ void ControllerBase::handleQueue() {
|
||||
|
||||
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||
changeHK(this->mode, this->submode, false);
|
||||
triggerEvent(CHANGING_MODE, mode_, submode_);
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
mode = mode_;
|
||||
submode = submode_;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
@ -82,6 +123,15 @@ ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
const ModeHelper* ControllerBase::getModeHelper() const { return &modeHelper; }
|
||||
|
||||
ActionHelper* ControllerBase::getActionHelper() { return &actionHelper; }
|
||||
|
||||
ReturnValue_t ControllerBase::executeAction(Action* action) { return action->handle(); }
|
||||
|
||||
DatapoolHelper* ControllerBase::getDatapoolHelper() { return &datapoolHelper; }
|
||||
HousekeepingHelper* ControllerBase::getHousekeepingHelper() { return &housekeepingHelper; }
|
||||
|
||||
void ControllerBase::modeChanged(Mode_t mode_, Submode_t submode_) {}
|
||||
|
||||
ReturnValue_t ControllerBase::setHealth(HealthState health) {
|
||||
@ -101,13 +151,3 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||
|
||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
||||
|
||||
const HasHealthIF* ControllerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& ControllerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/modes/ModeHelper.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
#include <fsfw/health/HasHealthIF.h>
|
||||
#include <fsfw/health/HealthHelper.h>
|
||||
#include <fsfw/introspection/ClasslessEnum.h>
|
||||
#include <fsfw/modes/HasModesIF.h>
|
||||
#include <fsfw/action/HasActionsIF.h>
|
||||
#include <fsfw/datapool/HasDatapoolIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
#include <fsfw/tasks/PeriodicTaskIF.h>
|
||||
|
||||
/**
|
||||
* @brief Generic base class for controller classes
|
||||
@ -20,19 +19,18 @@
|
||||
*/
|
||||
class ControllerBase : public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasDatapoolIF,
|
||||
public HasActionsIF,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
FSFW_CLASSLESS_ENUM(ControllerModes, Mode_t,
|
||||
((CONTROLLER_MODE_ON, MODE_ON, "On"))((CONTROLLER_MODE_OFF, MODE_OFF,
|
||||
"Off"))((MODE_NORMAL, 2, "Normal")))
|
||||
|
||||
ControllerBase(object_id_t setObjectId, size_t commandQueueDepth = 3);
|
||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
~ControllerBase() override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/** SystemObject override */
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -46,8 +44,17 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
void setTaskIF(PeriodicTaskIF *task) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
/** HasModeIF overrides */
|
||||
const ModeHelper *getModeHelper() const override;
|
||||
|
||||
/** HasActionsIF override */
|
||||
ActionHelper* getActionHelper() override;
|
||||
ReturnValue_t executeAction(Action* action) override;
|
||||
|
||||
/** HasDatapoolIF overrides */
|
||||
DatapoolHelper* getDatapoolHelper() override;
|
||||
HousekeepingHelper* getHousekeepingHelper() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -66,6 +73,8 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
Mode_t mode;
|
||||
|
||||
Submode_t submode;
|
||||
@ -76,6 +85,12 @@ class ControllerBase : public HasModesIF,
|
||||
|
||||
HealthHelper healthHelper;
|
||||
|
||||
ActionHelper actionHelper;
|
||||
|
||||
DatapoolHelper datapoolHelper;
|
||||
|
||||
HousekeepingHelper housekeepingHelper;
|
||||
|
||||
/**
|
||||
* Pointer to the task which executes this component,
|
||||
* is invalid before setTaskIF was called.
|
||||
|
@ -1,17 +1,19 @@
|
||||
#include "fsfw/controller/ExtendedControllerBase.h"
|
||||
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, commandQueueDepth),
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, parentId, commandQueueDepth),
|
||||
poolManager(this, commandQueue),
|
||||
actionHelper(this, commandQueue) {}
|
||||
|
||||
ExtendedControllerBase::~ExtendedControllerBase() = default;
|
||||
|
||||
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
|
||||
MessageQueueId_t commandedBy,
|
||||
const uint8_t *data, size_t size) {
|
||||
/* Needs to be overriden and implemented by child class. */
|
||||
return returnvalue::OK;
|
||||
ActionHelper *ExtendedControllerBase::getActionHelper() {
|
||||
return &actionHelper;
|
||||
}
|
||||
|
||||
ReturnValue_t ExtendedControllerBase::executeAction(Action *action) {
|
||||
return action->handle();
|
||||
}
|
||||
|
||||
object_id_t ExtendedControllerBase::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
@ -17,7 +17,7 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
public HasActionsIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth = 3);
|
||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
~ExtendedControllerBase() override;
|
||||
|
||||
/* SystemObjectIF overrides */
|
||||
@ -29,6 +29,10 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/* HasActionsIF overrides */
|
||||
ActionHelper* getActionHelper() override;
|
||||
ReturnValue_t executeAction(Action* actionId) override;
|
||||
|
||||
protected:
|
||||
LocalDataPoolManager poolManager;
|
||||
ActionHelper actionHelper;
|
||||
@ -49,10 +53,6 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
/* Handle the four messages mentioned above */
|
||||
void handleQueue() override;
|
||||
|
||||
/* HasActionsIF overrides */
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) override;
|
||||
|
||||
/* HasLocalDatapoolIF overrides */
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
[[nodiscard]] object_id_t getObjectId() const override;
|
||||
|
@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
|
||||
timeval timeSinceEpoch = time - epoch;
|
||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||
|
||||
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30;
|
||||
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
||||
|
||||
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) {
|
||||
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
||||
return TLE_TOO_OLD;
|
||||
}
|
||||
|
||||
|
@ -1 +1 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE Dataset.cpp DatapoolHelper.cpp)
|
||||
|
20
src/fsfw/datapool/DatapoolHelper.cpp
Normal file
20
src/fsfw/datapool/DatapoolHelper.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "DatapoolHelper.h"
|
||||
|
||||
DatapoolHelper::DatapoolHelper(HasDatapoolIF* owner) : HousekeepingHelper(owner) {}
|
||||
|
||||
ReturnValue_t DatapoolHelper::initialize() {
|
||||
return HousekeepingHelper::initialize();
|
||||
}
|
||||
|
||||
const Dataset* DatapoolHelper::getDataSet(HousekeepingSetId_t id) {
|
||||
auto iter = dataSets.find(id);
|
||||
if (iter == dataSets.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void DatapoolHelper::registerSet(Dataset* set) {
|
||||
auto id = set->getId();
|
||||
dataSets.emplace(id, set);
|
||||
}
|
28
src/fsfw/datapool/DatapoolHelper.h
Normal file
28
src/fsfw/datapool/DatapoolHelper.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dataset.h"
|
||||
#include "HasDatapoolIF.h"
|
||||
|
||||
#include <fsfw/housekeeping/HousekeepingHelper.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
|
||||
class DatapoolHelper : public HousekeepingHelper {
|
||||
public:
|
||||
DatapoolHelper(HasDatapoolIF *owner);
|
||||
~DatapoolHelper() = default;
|
||||
|
||||
const Dataset* getDataSet(HousekeepingSetId_t id);
|
||||
|
||||
const std::map<HousekeepingSetId_t, Dataset*>* getDatasets() const {
|
||||
return &dataSets;
|
||||
}
|
||||
|
||||
void registerSet(Dataset* set);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
private:
|
||||
std::map<HousekeepingSetId_t, Dataset*> dataSets;
|
||||
};
|
141
src/fsfw/datapool/Dataset.cpp
Normal file
141
src/fsfw/datapool/Dataset.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include "Dataset.h"
|
||||
|
||||
#include <fsfw/ipc/MutexFactory.h>
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
|
||||
//TODO for non allocated: detect if initialized, and if not, call it
|
||||
|
||||
#include "HasDatapoolIF.h"
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
Dataset::Dataset(HasDatapoolIF* owner, const EnumIF &id, bool allowUserCommit)
|
||||
: HousekeepingSet(owner, id), allocated(true), allowUserCommit(allowUserCommit) {
|
||||
this->owner.pointer = owner;
|
||||
owner->getDatapoolHelper()->registerSet(this);
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
Dataset::Dataset(uint32_t owner_id, const EnumIF &id)
|
||||
: HousekeepingSet(nullptr, id), allocated(false), allowUserCommit(false) {
|
||||
this->owner.id = owner_id;
|
||||
}
|
||||
#else
|
||||
Dataset::Dataset(HasDatapoolIF* owner, HousekeepingSetId_t id, bool allowUserCommit)
|
||||
: HousekeepingSet(owner, id), allocated(true), allowUserCommit(allowUserCommit) {
|
||||
this->owner.pointer = owner;
|
||||
owner->getDatapoolHelper()->registerSet(this);
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
Dataset::Dataset(uint32_t owner_id, HousekeepingSetId_t id) : HousekeepingSet(nullptr, id) {
|
||||
this->owner.id = owner_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
Dataset::~Dataset() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
|
||||
void Dataset::commit() {
|
||||
if ((!allocated) && (!allowUserCommit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock();
|
||||
for (auto variable : variables) {
|
||||
variable->commit();
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void Dataset::commit(bool valid) {
|
||||
if ((!allocated) && (!allowUserCommit)) {
|
||||
return;
|
||||
}
|
||||
setAllValid(valid);
|
||||
commit();
|
||||
}
|
||||
|
||||
void Dataset::setAllValid(bool valid) {
|
||||
if ((!allocated) && (!allowUserCommit)) {
|
||||
return;
|
||||
}
|
||||
for (auto variable : variables) {
|
||||
variable->setValid(valid);
|
||||
}
|
||||
}
|
||||
|
||||
void Dataset::read() {
|
||||
lock();
|
||||
for (auto variable : variables) {
|
||||
variable->read();
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool Dataset::hasChanged() {
|
||||
bool changed = hasChangedNoRead();
|
||||
read();
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool Dataset::hasChangedOrOlderThan(uint32_t seconds) {
|
||||
bool changed = hasChanged();
|
||||
// TODO time
|
||||
read();
|
||||
return changed;
|
||||
}
|
||||
|
||||
const std::vector<DatasetEntryIF*>* Dataset::getVariables() const { return &variables; }
|
||||
|
||||
ReturnValue_t Dataset::initialize() {
|
||||
if (allocated) {
|
||||
// nothing to do
|
||||
return returnvalue::OK;
|
||||
}
|
||||
HasDatapoolIF* actualOwner = ObjectManager::instance()->get<HasDatapoolIF>(owner.id);
|
||||
if (actualOwner == nullptr) {
|
||||
puts("owner type");
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
const Dataset* theOtherSet = actualOwner->getDatapoolHelper()->getDataSet(this->id);
|
||||
if (theOtherSet == nullptr) {
|
||||
puts("no set");
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (theOtherSet->variables.size() != variables.size()) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
this->mutex = theOtherSet->mutex;
|
||||
this->allowUserCommit = theOtherSet->allowUserCommit;
|
||||
|
||||
for (size_t i = 0; i < variables.size(); i++) {
|
||||
variables[i]->connect(theOtherSet->variables[i]);
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
// operator[]
|
||||
|
||||
|
||||
bool Dataset::registerEntry(DatasetEntryIF* entry) {
|
||||
variables.push_back(entry);
|
||||
return allocated;
|
||||
}
|
||||
|
||||
void Dataset::lock() { mutex->lockMutex(MutexIF::TimeoutType::BLOCKING); }
|
||||
|
||||
void Dataset::unlock() { mutex->unlockMutex(); }
|
||||
|
||||
bool Dataset::hasChangedNoRead() {
|
||||
bool changed = false;
|
||||
for (auto variable : variables) {
|
||||
if (variable->changed()) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
183
src/fsfw/datapool/Dataset.h
Normal file
183
src/fsfw/datapool/Dataset.h
Normal file
@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/housekeeping/HousekeepingSet.h>
|
||||
#include <fsfw/introspection/Enum.h>
|
||||
#include <fsfw/ipc/MutexIF.h>
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
#include <fsfw/storagemanager/storeAddress.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "DatasetEntryIF.h"
|
||||
|
||||
// TODO ring inclusion
|
||||
// #include "HasDatapoolIF.h"
|
||||
class HasDatapoolIF;
|
||||
|
||||
// TODO allow user commit and reporting TM
|
||||
|
||||
/**
|
||||
* This class has a dual use
|
||||
*
|
||||
* 1) It is used as an IPC method:
|
||||
* It implements a shared memory which can be written and read by different parties
|
||||
*
|
||||
* 2) It is used to define data that is to be downlinked, either periodically or
|
||||
* triggered by an (abstract, not in the sense of fsfw/events) event occuring, ie
|
||||
* data was received from an external source and should be shared with ground.
|
||||
*
|
||||
* Generating a downlinked report is coupled to commiting, as without a commit there is no
|
||||
* change in information to be reported.
|
||||
*
|
||||
* Nominally, the decision to report is done by the set itself, depending on its settings.
|
||||
* If a report is to be forced regardless of these settings, the commitAndReport() functions
|
||||
* are provided which will always generate a report.
|
||||
*
|
||||
* Periodic reports are not tied to a specific tc and are reported as "unrequested". When forcing
|
||||
* a report, optionally a tc can be provided which (logically) triggered the report.
|
||||
*
|
||||
* And, as life is complicated, there is a third set of commits: commitAndReportIfRequested(). Same
|
||||
* as before, but this time, a report is only generated, if the store_address_t is valid. These are
|
||||
* used if at the place where the commit is called, it is not known if there is a request (cf DHB
|
||||
* interpretDeviceReply)
|
||||
*/
|
||||
|
||||
class Dataset : public HousekeepingSet {
|
||||
protected:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
Dataset(HasDatapoolIF* owner, const EnumIF &id, bool allowUserCommit);
|
||||
Dataset(uint32_t owner_id, const EnumIF &id);
|
||||
#else
|
||||
Dataset(HasDatapoolIF* owner, HousekeepingSetId_t id, bool allowUserCommit);
|
||||
Dataset(uint32_t owner_id, HousekeepingSetId_t id);
|
||||
#endif
|
||||
public:
|
||||
~Dataset() override;
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
*
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
*
|
||||
* calls setValid(valid) before committing
|
||||
*
|
||||
*/
|
||||
void commit(bool valid);
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet
|
||||
*
|
||||
*/
|
||||
void commitAndReport();
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet
|
||||
*
|
||||
* calls setValid(valid) before committing
|
||||
*
|
||||
*/
|
||||
void commitAndReport(bool valid);
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet, in reference to tc
|
||||
*
|
||||
*/
|
||||
void commitAndReport(store_address_t tc, size_t tc_offset);
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet, in reference to tc
|
||||
*
|
||||
* calls setValid(valid) before committing
|
||||
*
|
||||
*/
|
||||
void commitAndReport(bool valid, store_address_t tc, size_t tc_offset);
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet, in reference to tc, if tc is valid
|
||||
*
|
||||
*/
|
||||
void commitAndReportIfRequested(store_address_t tc, size_t tc_offset);
|
||||
|
||||
/**
|
||||
* Copy content of local copies into actual variable
|
||||
* Force sending of TM packet, in reference to tc, if tc is valid
|
||||
*
|
||||
* calls setValid(valid) before committing
|
||||
*
|
||||
*/
|
||||
void commitAndReportIfRequested(bool valid, store_address_t tc, size_t tc_offset);
|
||||
|
||||
/**
|
||||
* set all contained variables to #valid
|
||||
*
|
||||
*/
|
||||
void setAllValid(bool valid);
|
||||
|
||||
/**
|
||||
* Copy content of actual variables into local copies
|
||||
*
|
||||
*
|
||||
*/
|
||||
void read();
|
||||
|
||||
/**
|
||||
* returns true if local copies and actual variables differ
|
||||
*
|
||||
* implicitely calls read()
|
||||
*/
|
||||
bool hasChanged();
|
||||
|
||||
/**
|
||||
* returns true if local copies and actual variables differ
|
||||
* or time since last time true has been returned is greater than
|
||||
* supplied time
|
||||
*
|
||||
* implicitely calls read()
|
||||
*
|
||||
*/
|
||||
bool hasChangedOrOlderThan(uint32_t seconds);
|
||||
|
||||
/**
|
||||
* get List of contained Valiables
|
||||
*/
|
||||
virtual const std::vector<DatasetEntryIF*>* getVariables() const;
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
// operator[]
|
||||
|
||||
bool registerEntry(DatasetEntryIF*);
|
||||
|
||||
protected:
|
||||
|
||||
bool allocated;
|
||||
bool allowUserCommit;
|
||||
union {
|
||||
object_id_t id;
|
||||
HasDatapoolIF* pointer;
|
||||
} owner;
|
||||
MutexIF* mutex;
|
||||
|
||||
std::vector<DatasetEntryIF*> variables;
|
||||
|
||||
/**
|
||||
* lock the mutex of the set
|
||||
*/
|
||||
void lock();
|
||||
|
||||
/**
|
||||
* unlock the mutex of the set
|
||||
*/
|
||||
void unlock();
|
||||
|
||||
bool hasChangedNoRead();
|
||||
};
|
87
src/fsfw/datapool/DatasetEntry.h
Normal file
87
src/fsfw/datapool/DatasetEntry.h
Normal file
@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/introspection/Parameter.h>
|
||||
#include <fsfw/introspection/Types.h>
|
||||
#include <fsfw/introspection/TypesHelper.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Dataset.h"
|
||||
#include "DatasetEntryIF.h"
|
||||
// TODO: ifdef introspection stuff
|
||||
|
||||
template <typename T>
|
||||
class DatasetEntry : public Parameter<T>, public DatasetEntryIF {
|
||||
protected:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
DatasetEntry(Dataset *owner, const char *name)
|
||||
: Parameter<T>(owner, name)
|
||||
#else
|
||||
DatasetEntry(Dataset *owner)
|
||||
: Parameter<T>(owner)
|
||||
#endif
|
||||
{
|
||||
allocated = owner->registerEntry(this);
|
||||
if (!allocated) {
|
||||
return;
|
||||
}
|
||||
storedValue = new T();
|
||||
storedValid = new bool;
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
static DatasetEntry createDatasetEntry(Dataset *owner, const char *name) {
|
||||
return DatasetEntry(owner, name);
|
||||
}
|
||||
#else
|
||||
static DatasetEntry createDatasetEntry(Dataset *owner) { return DatasetEntry(owner); }
|
||||
#endif
|
||||
|
||||
~DatasetEntry() {
|
||||
if (allocated) {
|
||||
delete storedValue;
|
||||
delete storedValid;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setValid(bool isValid) { valid = isValid; }
|
||||
|
||||
virtual bool getValid() { return valid; }
|
||||
|
||||
//T value; //TODO can this be private?
|
||||
|
||||
protected:
|
||||
virtual void commit() {
|
||||
*storedValue = Parameter<T>::value;
|
||||
*storedValid = valid;
|
||||
}
|
||||
virtual void read() {
|
||||
Parameter<T>::value = *storedValue;
|
||||
valid = *storedValid;
|
||||
}
|
||||
|
||||
virtual void connect(DatasetEntryIF *entry) {
|
||||
DatasetEntry<T> *theOther = dynamic_cast<DatasetEntry<T> *>(entry);
|
||||
if (theOther == nullptr) {
|
||||
// Configuration error
|
||||
return;
|
||||
}
|
||||
this->storedValue = theOther->storedValue;
|
||||
this->storedValid = theOther->storedValid;
|
||||
}
|
||||
|
||||
virtual bool changed() { return ((Parameter<T>::value != *storedValue) || (valid != *storedValid)); }
|
||||
|
||||
private:
|
||||
|
||||
T *storedValue;
|
||||
bool *storedValid;
|
||||
bool valid;
|
||||
bool allocated;
|
||||
};
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
#define createDatasetEntry(p1, p2) createDatasetEntry(p1, p2)
|
||||
#else
|
||||
#define createDatasetEntry(p1, p2) createDatasetEntry(p1)
|
||||
#endif
|
39
src/fsfw/datapool/DatasetEntryIF.h
Normal file
39
src/fsfw/datapool/DatasetEntryIF.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLENTRYIF_H_
|
||||
#define FSFW_DATAPOOL_POOLENTRYIF_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <fsfw/introspection/Types.h>
|
||||
|
||||
class DatasetEntryIF {
|
||||
friend class Dataset;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~DatasetEntryIF() {}
|
||||
/**
|
||||
* @brief This method allows to set the valid information of the pool entry.
|
||||
*/
|
||||
virtual void setValid(bool isValid) = 0;
|
||||
/**
|
||||
* @brief This method allows to set the valid information of the pool entry.
|
||||
*/
|
||||
virtual bool getValid() = 0;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void commit() = 0;
|
||||
virtual void read() = 0;
|
||||
virtual void connect(DatasetEntryIF* entry) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* returns if value and actual value is different
|
||||
*/
|
||||
virtual bool changed() = 0;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */
|
13
src/fsfw/datapool/HasDatapoolIF.h
Normal file
13
src/fsfw/datapool/HasDatapoolIF.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
//TODO ring
|
||||
class DatapoolHelper;
|
||||
#include "DatapoolHelper.h"
|
||||
|
||||
#include <fsfw/housekeeping/GeneratesHousekeepingIF.h>
|
||||
|
||||
class HasDatapoolIF: public GeneratesHousekeepingIF {
|
||||
public:
|
||||
virtual ~HasDatapoolIF() = default;
|
||||
virtual DatapoolHelper* getDatapoolHelper() = 0;
|
||||
};
|
@ -1,217 +0,0 @@
|
||||
#include "fsfw/datapool/PoolDataSetBase.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/datapool/ReadCommitIFAttorney.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
|
||||
const size_t maxFillCount)
|
||||
: registeredVariables(registeredVariablesArray), maxFillCount(maxFillCount) {}
|
||||
|
||||
PoolDataSetBase::~PoolDataSetBase() {}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF* variable) {
|
||||
if (registeredVariables == nullptr) {
|
||||
/* Underlying container invalid */
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (state != States::STATE_SET_UNINITIALISED) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
|
||||
#else
|
||||
sif::printError("DataSet::registerVariable: Call made in wrong position.");
|
||||
#endif
|
||||
return DataSetIF::DATA_SET_UNINITIALISED;
|
||||
}
|
||||
if (variable == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl;
|
||||
#else
|
||||
sif::printError("DataSet::registerVariable: Pool variable is nullptr.\n");
|
||||
#endif
|
||||
return DataSetIF::POOL_VAR_NULL;
|
||||
}
|
||||
if (fillCount >= maxFillCount) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DataSet::registerVariable: DataSet is full." << std::endl;
|
||||
#else
|
||||
sif::printError("DataSet::registerVariable: DataSet is full.\n");
|
||||
#endif
|
||||
return DataSetIF::DATA_SET_FULL;
|
||||
}
|
||||
registeredVariables[fillCount] = variable;
|
||||
fillCount++;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
ReturnValue_t error = result;
|
||||
if (state == States::STATE_SET_UNINITIALISED) {
|
||||
lockDataPool(timeoutType, lockTimeout);
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
result = readVariable(count);
|
||||
if (result != returnvalue::OK) {
|
||||
error = result;
|
||||
}
|
||||
}
|
||||
state = States::STATE_SET_WAS_READ;
|
||||
unlockDataPool();
|
||||
} else {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||
"commit member datasets!"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"PoolDataSetBase::read: Call made in wrong position. Don't forget to "
|
||||
"commit member datasets!\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
result = SET_WAS_ALREADY_READ;
|
||||
}
|
||||
|
||||
if (error != returnvalue::OK) {
|
||||
result = error;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t PoolDataSetBase::getFillCount() const { return fillCount; }
|
||||
|
||||
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
if (registeredVariables[count] == nullptr) {
|
||||
/* Configuration error. */
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
/* These checks are often performed by the respective variable implementation too, but I guess
|
||||
a double check does not hurt. */
|
||||
if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_WRITE and
|
||||
registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
|
||||
if (protectEveryReadCommitCall) {
|
||||
result =
|
||||
registeredVariables[count]->read(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
|
||||
} else {
|
||||
/* The readWithoutLock function is protected, so we use the attorney here */
|
||||
result = ReadCommitIFAttorney::readWithoutLock(registeredVariables[count]);
|
||||
}
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
result = INVALID_PARAMETER_DEFINITION;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
|
||||
if (state == States::STATE_SET_WAS_READ) {
|
||||
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
return handleUnreadDatasetCommit(timeoutType, lockTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolDataSetBase::handleAlreadyReadDatasetCommit(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t lockTimeout) {
|
||||
lockDataPool(timeoutType, lockTimeout);
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
if ((registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) and
|
||||
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
|
||||
if (protectEveryReadCommitCall) {
|
||||
registeredVariables[count]->commit(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
|
||||
} else {
|
||||
/* The commitWithoutLock function is protected, so we use the attorney here */
|
||||
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
|
||||
}
|
||||
}
|
||||
}
|
||||
state = States::STATE_SET_UNINITIALISED;
|
||||
unlockDataPool();
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t lockTimeout) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
lockDataPool(timeoutType, lockTimeout);
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
if ((registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE) and
|
||||
(registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
|
||||
if (protectEveryReadCommitCall) {
|
||||
result =
|
||||
registeredVariables[count]->commit(timeoutTypeForSingleVars, mutexTimeoutForSingleVars);
|
||||
} else {
|
||||
/* The commitWithoutLock function is protected, so we use the attorney here */
|
||||
ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
|
||||
}
|
||||
|
||||
} else if (registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
|
||||
if (result != COMMITING_WITHOUT_READING) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "DataSet::commit(): commit-without-read call made "
|
||||
"with non write-only variable."
|
||||
<< std::endl;
|
||||
#endif
|
||||
result = COMMITING_WITHOUT_READING;
|
||||
}
|
||||
}
|
||||
}
|
||||
state = States::STATE_SET_UNINITIALISED;
|
||||
unlockDataPool();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
|
||||
uint32_t lockTimeout) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::unlockDataPool() { return returnvalue::OK; }
|
||||
|
||||
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
result = registeredVariables[count]->deSerialize(buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t PoolDataSetBase::getSerializedSize() const {
|
||||
uint32_t size = 0;
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
size += registeredVariables[count]->getSerializedSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void PoolDataSetBase::setContainer(PoolVariableIF** variablesContainer) {
|
||||
this->registeredVariables = variablesContainer;
|
||||
}
|
||||
|
||||
PoolVariableIF** PoolDataSetBase::getContainer() const { return registeredVariables; }
|
||||
|
||||
void PoolDataSetBase::setReadCommitProtectionBehaviour(bool protectEveryReadCommit,
|
||||
MutexIF::TimeoutType timeoutType,
|
||||
uint32_t mutexTimeout) {
|
||||
this->protectEveryReadCommitCall = protectEveryReadCommit;
|
||||
this->timeoutTypeForSingleVars = timeoutType;
|
||||
this->mutexTimeoutForSingleVars = mutexTimeout;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLDATASETBASE_H_
|
||||
#define FSFW_DATAPOOL_POOLDATASETBASE_H_
|
||||
|
||||
#include "PoolDataSetIF.h"
|
||||
#include "PoolVariableIF.h"
|
||||
#include "fsfw/ipc/MutexIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief The DataSetBase class manages a set of locally checked out variables.
|
||||
* @details
|
||||
* This class manages a list, where a set of local variables (or pool variables)
|
||||
* are registered. They are checked-out (i.e. their values are looked
|
||||
* up and copied) with the read call. After the user finishes working with the
|
||||
* pool variables, he can write back all variable values to the pool with
|
||||
* the commit call. The data set manages locking and freeing the data pool,
|
||||
* to ensure that all values are read and written back at once.
|
||||
*
|
||||
* An internal state manages usage of this class. Variables may only be
|
||||
* registered before the read call is made, and the commit call only
|
||||
* after the read call.
|
||||
*
|
||||
* If pool variables are writable and not committed until destruction
|
||||
* of the set, the DataSet class automatically sets the valid flag in the
|
||||
* data pool to invalid (without) changing the variable's value.
|
||||
*
|
||||
* The base class lockDataPool und unlockDataPool implementation are empty
|
||||
* and should be implemented to protect the underlying pool type.
|
||||
* @author Bastian Baetz
|
||||
* @ingroup data_pool
|
||||
*/
|
||||
class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an empty dataset. Use registerVariable or
|
||||
* supply a pointer to this dataset to PoolVariable
|
||||
* initializations to register pool variables.
|
||||
*/
|
||||
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, size_t maxFillCount);
|
||||
|
||||
/* Forbidden for now */
|
||||
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
|
||||
const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete;
|
||||
|
||||
~PoolDataSetBase() override;
|
||||
|
||||
/**
|
||||
* @brief The read call initializes reading out all registered variables.
|
||||
* It is mandatory to call commit after every read call!
|
||||
* @details
|
||||
* It iterates through the list of registered variables and calls all read()
|
||||
* functions of the registered pool variables (which read out their values
|
||||
* from the data pool) which are not write-only.
|
||||
* In case of an error (e.g. a wrong data type, or an invalid data pool id),
|
||||
* the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned.
|
||||
*
|
||||
* The data pool is locked during the whole read operation and
|
||||
* freed afterwards. It is mandatory to call commit after a read call,
|
||||
* even if the read operation is not successful!
|
||||
* @return
|
||||
* - @c returnvalue::OK if all variables were read successfully.
|
||||
* - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
|
||||
* is a type conflict.
|
||||
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
|
||||
* commit() in between
|
||||
*/
|
||||
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
/**
|
||||
* @brief The commit call initializes writing back the registered variables.
|
||||
* @details
|
||||
* It iterates through the list of registered variables and calls the
|
||||
* commit() method of the remaining registered variables (which write back
|
||||
* their values to the pool).
|
||||
*
|
||||
* The data pool is locked during the whole commit operation and
|
||||
* freed afterwards. The state changes to "was committed" after this operation.
|
||||
*
|
||||
* If the set does contain at least one variable which is not write-only
|
||||
* commit() can only be called after read(). If the set only contains
|
||||
* variables which are write only, commit() can be called without a
|
||||
* preceding read() call. Every read call must be followed by a commit call!
|
||||
* @return - @c returnvalue::OK if all variables were read successfully.
|
||||
* - @c COMMITING_WITHOUT_READING if set was not read yet and
|
||||
* contains non write-only variables
|
||||
*/
|
||||
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t lockTimeout = 20) override;
|
||||
|
||||
/**
|
||||
* Register the passed pool variable instance into the data set.
|
||||
* @param variable
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) override;
|
||||
|
||||
/**
|
||||
* Provides the means to lock the underlying data structure to ensure
|
||||
* thread-safety. Default implementation is empty
|
||||
* @return Always returns -@c returnvalue::OK
|
||||
*/
|
||||
virtual ReturnValue_t lockDataPool(
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t timeoutMs = 20) override;
|
||||
/**
|
||||
* Provides the means to unlock the underlying data structure to ensure
|
||||
* thread-safety. Default implementation is empty
|
||||
* @return Always returns -@c returnvalue::OK
|
||||
*/
|
||||
virtual ReturnValue_t unlockDataPool() override;
|
||||
|
||||
virtual uint16_t getFillCount() const override;
|
||||
|
||||
/* SerializeIF implementations */
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override;
|
||||
virtual size_t getSerializedSize() const override;
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
|
||||
/**
|
||||
* Can be used to individually protect every read and commit call.
|
||||
* @param protectEveryReadCommit
|
||||
* @param mutexTimeout
|
||||
*/
|
||||
void setReadCommitProtectionBehaviour(
|
||||
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t mutexTimeout = 20);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief The fill_count attribute ensures that the variables
|
||||
* register in the correct array position and that the maximum
|
||||
* number of variables is not exceeded.
|
||||
*/
|
||||
uint16_t fillCount = 0;
|
||||
/**
|
||||
* States of the seet.
|
||||
*/
|
||||
enum class States {
|
||||
STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
|
||||
STATE_SET_WAS_READ //!< DATA_SET_WAS_READ
|
||||
};
|
||||
/**
|
||||
* @brief state manages the internal state of the data set,
|
||||
* which is important e.g. for the behavior on destruction.
|
||||
*/
|
||||
States state = States::STATE_SET_UNINITIALISED;
|
||||
|
||||
/**
|
||||
* @brief This array represents all pool variables registered in this set.
|
||||
* Child classes can use a static or dynamic container to create
|
||||
* an array of registered variables and assign the first entry here.
|
||||
*/
|
||||
PoolVariableIF** registeredVariables = nullptr;
|
||||
const size_t maxFillCount = 0;
|
||||
|
||||
void setContainer(PoolVariableIF** variablesContainer);
|
||||
PoolVariableIF** getContainer() const;
|
||||
|
||||
private:
|
||||
bool protectEveryReadCommitCall = false;
|
||||
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t mutexTimeoutForSingleVars = 20;
|
||||
|
||||
ReturnValue_t readVariable(uint16_t count);
|
||||
void handleAlreadyReadDatasetCommit(
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, uint32_t timeoutMs = 20);
|
||||
ReturnValue_t handleUnreadDatasetCommit(
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, uint32_t timeoutMs = 20);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */
|
@ -1,34 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLDATASETIF_H_
|
||||
#define FSFW_DATAPOOL_POOLDATASETIF_H_
|
||||
|
||||
#include "DataSetIF.h"
|
||||
#include "ReadCommitIF.h"
|
||||
|
||||
/**
|
||||
* @brief Extendes the DataSetIF by adding abstract functions to lock
|
||||
* and unlock a data pool and read/commit semantics.
|
||||
*/
|
||||
class PoolDataSetIF : virtual public DataSetIF, virtual public ReadCommitIF {
|
||||
public:
|
||||
virtual ~PoolDataSetIF(){};
|
||||
|
||||
/**
|
||||
* @brief Most underlying data structures will have a pool like structure
|
||||
* and will require a lock and unlock mechanism to ensure
|
||||
* thread-safety
|
||||
* @return Lock operation result
|
||||
*/
|
||||
virtual ReturnValue_t lockDataPool(
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t timeoutMs = 20) = 0;
|
||||
|
||||
/**
|
||||
* @brief Unlock call corresponding to the lock call.
|
||||
* @return Unlock operation result
|
||||
*/
|
||||
virtual ReturnValue_t unlockDataPool() = 0;
|
||||
|
||||
virtual bool isValid() const = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLDATASETIF_H_ */
|
@ -1,102 +0,0 @@
|
||||
#include "fsfw/datapool/PoolEntry.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(uint8_t len, bool setValid) : length(len), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
std::memset(this->address, 0, this->getByteSize());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(std::initializer_list<T> initValues, bool setValid)
|
||||
: length(static_cast<uint8_t>(initValues.size())), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
if (initValues.size() > 0) {
|
||||
std::copy(initValues.begin(), initValues.end(), this->address);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PoolEntry<T>::PoolEntry(const T* initValue, uint8_t setLength, bool setValid)
|
||||
: length(setLength), valid(setValid) {
|
||||
this->address = new T[this->length]();
|
||||
if (initValue != nullptr) {
|
||||
std::memcpy(this->address, initValue, this->getByteSize());
|
||||
}
|
||||
}
|
||||
|
||||
// As the data pool is global, this dtor is only be called on program exit.
|
||||
// Warning! Never copy pool entries!
|
||||
template <typename T>
|
||||
PoolEntry<T>::~PoolEntry() {
|
||||
delete[] this->address;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint16_t PoolEntry<T>::getByteSize() {
|
||||
return (sizeof(T) * this->length);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
uint8_t PoolEntry<T>::getSize() {
|
||||
return this->length;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void* PoolEntry<T>::getRawData() {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PoolEntry<T>::setValid(bool isValid) {
|
||||
this->valid = isValid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool PoolEntry<T>::getValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PoolEntry<T>::print() {
|
||||
const char* validString = nullptr;
|
||||
if (valid) {
|
||||
validString = "Valid";
|
||||
} else {
|
||||
validString = "Invalid";
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "PoolEntry information." << std::endl;
|
||||
sif::info << "PoolEntry validity: " << validString << std::endl;
|
||||
#else
|
||||
sif::printInfo("PoolEntry information.\n");
|
||||
sif::printInfo("PoolEntry validity: %s\n", validString);
|
||||
#endif
|
||||
arrayprinter::print(reinterpret_cast<uint8_t*>(address), getByteSize());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* PoolEntry<T>::getDataPtr() {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Type PoolEntry<T>::getType() {
|
||||
return PodTypeConversion<T>::type;
|
||||
}
|
||||
|
||||
template class PoolEntry<uint8_t>;
|
||||
template class PoolEntry<uint16_t>;
|
||||
template class PoolEntry<uint32_t>;
|
||||
template class PoolEntry<uint64_t>;
|
||||
template class PoolEntry<int8_t>;
|
||||
template class PoolEntry<int16_t>;
|
||||
template class PoolEntry<int32_t>;
|
||||
template class PoolEntry<int64_t>;
|
||||
template class PoolEntry<float>;
|
||||
template class PoolEntry<double>;
|
@ -1,140 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLENTRY_H_
|
||||
#define FSFW_DATAPOOL_POOLENTRY_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
|
||||
#include "PoolEntryIF.h"
|
||||
|
||||
/**
|
||||
* @brief This is a small helper class that defines a single data pool entry.
|
||||
* @details
|
||||
* The helper is used to store all information together with the data as a
|
||||
* single data pool entry. The content's type is defined by the template
|
||||
* argument.
|
||||
*
|
||||
* It is prepared for use with plain old data types, but may be
|
||||
* extended to complex types if necessary. It can be initialized with a
|
||||
* certain value, size and validity flag.
|
||||
*
|
||||
* It holds a pointer to the real data and offers methods to access this data
|
||||
* and to acquire additional information (such as validity and array/byte size).
|
||||
* It is NOT intended to be used outside DataPool implementations as it performs
|
||||
* dynamic memory allocation.
|
||||
*
|
||||
* @ingroup data_pool
|
||||
*/
|
||||
template <typename T>
|
||||
class PoolEntry : public PoolEntryIF {
|
||||
public:
|
||||
static_assert(not std::is_same<T, bool>::value,
|
||||
"Do not use boolean for the PoolEntry type, use uint8_t "
|
||||
"instead! The ECSS standard defines a boolean as a one bit "
|
||||
"field. Therefore it is preferred to store a boolean as an "
|
||||
"uint8_t");
|
||||
|
||||
PoolEntry(uint8_t len = 1, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
* potential initialization values are copied to that space.
|
||||
* @details
|
||||
* Not passing any arguments will initialize an non-array pool entry
|
||||
* with an initial invalid state and the value 0.
|
||||
* Please note that if an initializer list is passed, the length of the
|
||||
* initializer list needs to be correct for vector entries because
|
||||
* required allocated space will be deduced from the initializer list length
|
||||
* and the pool entry type.
|
||||
* @param initValue
|
||||
* Initializer list with values to initialize with, for example {0, 0} to
|
||||
* initialize the a pool entry of a vector with two entries to 0.
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(std::initializer_list<T> initValue, bool setValid = false);
|
||||
|
||||
/**
|
||||
* @brief In the classe's constructor, space is allocated on the heap and
|
||||
* potential init values are copied to that space.
|
||||
* @param initValue
|
||||
* A pointer to the single value or array that holds the init value.
|
||||
* With the default value (nullptr), the entry is initalized with all 0.
|
||||
* @param setLength
|
||||
* Defines the array length of this entry.
|
||||
* @param setValid
|
||||
* Sets the initialization flag. It is invalid by default.
|
||||
*/
|
||||
PoolEntry(const T* initValue, uint8_t setLength = 1, bool setValid = false);
|
||||
|
||||
//! Explicitely deleted copy ctor, copying is not allowed.
|
||||
PoolEntry(const PoolEntry&) = delete;
|
||||
//! Explicitely deleted copy assignment, copying is not allowed.
|
||||
PoolEntry& operator=(const PoolEntry&) = delete;
|
||||
|
||||
/**
|
||||
* @brief The allocated memory for the variable is freed
|
||||
* in the destructor.
|
||||
* @details
|
||||
* As the data pool is global, this dtor is only called on program exit.
|
||||
* PoolEntries shall never be copied, as a copy might delete the variable
|
||||
* on the heap.
|
||||
*/
|
||||
~PoolEntry();
|
||||
|
||||
/**
|
||||
* Return typed pointer to start of data.
|
||||
* @return
|
||||
*/
|
||||
T* getDataPtr();
|
||||
|
||||
/**
|
||||
* @brief getSize returns the array size of the entry.
|
||||
* @details
|
||||
* For non-array pool entries return type size, for vector entries
|
||||
* return type size times the number of entries.
|
||||
*/
|
||||
uint8_t getSize();
|
||||
/**
|
||||
* @brief This operation returns the size in bytes.
|
||||
* @details The size is calculated by sizeof(type) * array_size.
|
||||
*/
|
||||
uint16_t getByteSize();
|
||||
/**
|
||||
* @brief This operation returns a the address pointer casted to void*.
|
||||
*/
|
||||
void* getRawData();
|
||||
/**
|
||||
* @brief This method allows to set the valid information
|
||||
* of the pool entry.
|
||||
*/
|
||||
void setValid(bool isValid);
|
||||
/**
|
||||
* @brief This method allows to get the valid information
|
||||
* of the pool entry.
|
||||
*/
|
||||
bool getValid();
|
||||
/**
|
||||
* @brief This is a debug method that prints all values and the valid
|
||||
* information to the screen. It prints all array entries in a row.
|
||||
*/
|
||||
void print();
|
||||
Type getType();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief This attribute stores the length information.
|
||||
*/
|
||||
uint8_t length;
|
||||
/**
|
||||
* @brief Here, the validity information for a variable is stored.
|
||||
* Every entry (single variable or vector) has one valid flag.
|
||||
*/
|
||||
uint8_t valid;
|
||||
/**
|
||||
* @brief This is the address pointing to the allocated memory.
|
||||
*/
|
||||
T* address;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLENTRY_H_ */
|
@ -1,28 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLVARLIST_H_
|
||||
#define FSFW_DATAPOOL_POOLVARLIST_H_
|
||||
|
||||
#include "../datapool/PoolVariableIF.h"
|
||||
#include "../datapoolglob/GlobalPoolVariable.h"
|
||||
template <class T, uint8_t n_var>
|
||||
class PoolVarList {
|
||||
private:
|
||||
GlobPoolVar<T> variables[n_var];
|
||||
|
||||
public:
|
||||
PoolVarList(const uint32_t set_id[n_var], DataSetIF* dataSet,
|
||||
PoolVariableIF::ReadWriteMode_t setReadWriteMode) {
|
||||
// I really should have a look at the new init list c++ syntax.
|
||||
if (dataSet == NULL) {
|
||||
return;
|
||||
}
|
||||
for (uint8_t count = 0; count < n_var; count++) {
|
||||
variables[count].dataPoolId = set_id[count];
|
||||
variables[count].readWriteMode = setReadWriteMode;
|
||||
dataSet->registerVariable(&variables[count]);
|
||||
}
|
||||
}
|
||||
|
||||
GlobPoolVar<T>& operator[](int i) { return variables[i]; }
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLVARLIST_H_ */
|
@ -1,62 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_
|
||||
#define FSFW_DATAPOOL_POOLVARIABLEIF_H_
|
||||
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "ReadCommitIF.h"
|
||||
|
||||
/**
|
||||
* @brief This interface is used to control data pool
|
||||
* variable representations.
|
||||
* @details
|
||||
* To securely handle data pool variables, all pool entries are locally
|
||||
* managed by data pool variable access classes, which are called pool
|
||||
* variables. To ensure a common state of a set of variables needed in a
|
||||
* function, these local pool variables again are managed by other classes,
|
||||
* like the DataSet classes. This interface provides unified access to
|
||||
* local pool variables for such manager classes.
|
||||
* @author Bastian Baetz
|
||||
* @ingroup data_pool
|
||||
*/
|
||||
class PoolVariableIF : public SerializeIF, public ReadCommitIF {
|
||||
public:
|
||||
static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF;
|
||||
static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0);
|
||||
static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1);
|
||||
|
||||
static constexpr bool VALID = 1;
|
||||
static constexpr bool INVALID = 0;
|
||||
static constexpr uint32_t NO_PARAMETER = 0xffffffff;
|
||||
|
||||
enum ReadWriteMode_t { VAR_READ, VAR_WRITE, VAR_READ_WRITE };
|
||||
|
||||
/**
|
||||
* @brief This is an empty virtual destructor,
|
||||
* as it is proposed for C++ interfaces.
|
||||
*/
|
||||
virtual ~PoolVariableIF() {}
|
||||
/**
|
||||
* @brief This method returns if the variable is write-only,
|
||||
* read-write or read-only.
|
||||
*/
|
||||
virtual ReadWriteMode_t getReadWriteMode() const = 0;
|
||||
virtual void setReadWriteMode(ReadWriteMode_t newMode) = 0;
|
||||
|
||||
/**
|
||||
* @brief This operation shall return the data pool id of the variable.
|
||||
*/
|
||||
virtual uint32_t getDataPoolId() const = 0;
|
||||
/**
|
||||
* @brief With this call, the valid information of the
|
||||
* variable is returned.
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
/**
|
||||
* @brief With this call, the valid information of the variable is set.
|
||||
*/
|
||||
virtual void setValid(bool validity) = 0;
|
||||
};
|
||||
|
||||
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLVARIABLEIF_H_ */
|
@ -1,27 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_READCOMMITIF_H_
|
||||
#define FSFW_DATAPOOL_READCOMMITIF_H_
|
||||
|
||||
#include "../ipc/MutexIF.h"
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
|
||||
/**
|
||||
* @brief Common interface for all software objects which employ read-commit
|
||||
* semantics.
|
||||
*/
|
||||
class ReadCommitIF {
|
||||
friend class ReadCommitIFAttorney;
|
||||
|
||||
public:
|
||||
virtual ~ReadCommitIF() {}
|
||||
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) = 0;
|
||||
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) = 0;
|
||||
|
||||
protected:
|
||||
/* Optional and protected because this is interesting for classes grouping members with commit
|
||||
and read semantics where the lock is only necessary once. */
|
||||
virtual ReturnValue_t readWithoutLock() { return read(MutexIF::TimeoutType::WAITING, 20); }
|
||||
|
||||
virtual ReturnValue_t commitWithoutLock() { return commit(MutexIF::TimeoutType::WAITING, 20); }
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_READCOMMITIF_H_ */
|
@ -1,30 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
|
||||
#define FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
|
||||
|
||||
#include <fsfw/datapool/ReadCommitIF.h>
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
|
||||
/**
|
||||
* @brief This class determines which members are allowed to access protected members
|
||||
* of the ReadCommitIF.
|
||||
*/
|
||||
class ReadCommitIFAttorney {
|
||||
private:
|
||||
static ReturnValue_t readWithoutLock(ReadCommitIF* readCommitIF) {
|
||||
if (readCommitIF == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return readCommitIF->readWithoutLock();
|
||||
}
|
||||
|
||||
static ReturnValue_t commitWithoutLock(ReadCommitIF* readCommitIF) {
|
||||
if (readCommitIF == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return readCommitIF->commitWithoutLock();
|
||||
}
|
||||
|
||||
friend class PoolDataSetBase;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_ */
|
@ -1,16 +0,0 @@
|
||||
#ifndef FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
||||
#define FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_
|
||||
|
||||
#include "PoolDataSetIF.h"
|
||||
|
||||
class SharedDataSetIF {
|
||||
public:
|
||||
virtual ~SharedDataSetIF(){};
|
||||
|
||||
private:
|
||||
virtual ReturnValue_t lockDataset(MutexIF::TimeoutType timeoutType,
|
||||
dur_millis_t mutexTimeout) = 0;
|
||||
virtual ReturnValue_t unlockDataset() = 0;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_DATAPOOL_SHAREDDATASETIF_H_ */
|
@ -1,11 +0,0 @@
|
||||
#ifndef FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
|
||||
#define FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_
|
||||
|
||||
/* Collected related headers */
|
||||
#include "fsfw/datapoollocal/LocalDataSet.h"
|
||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||
#include "fsfw/datapoollocal/LocalPoolVector.h"
|
||||
#include "fsfw/datapoollocal/SharedLocalDataSet.h"
|
||||
#include "fsfw/datapoollocal/StaticLocalDataSet.h"
|
||||
|
||||
#endif /* FSFW_DATAPOOLLOCAL_DATAPOOLLOCAL_H_ */
|
@ -1,7 +1,7 @@
|
||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, MODE_OFF, commandQueueDepth),
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE),
|
||||
recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()),
|
||||
@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
triggerModeHelperEvents(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
// The user needs to take care of commanding the children off in commandChildren
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||
// to wait for an off time period.
|
||||
// TODO: make time period configurable
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,7 @@
|
||||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
* This class reduces the complexity of controller components which would
|
||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||
* manage the mode keeping and recovery of non-redundant devices
|
||||
* otherwise be needed for the handling of redundant devices.
|
||||
*
|
||||
* The template class monitors mode and health state of its children
|
||||
* and checks availability of devices on every detected change.
|
||||
@ -27,9 +26,11 @@
|
||||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call #registerChild for all commanded children during initialization.
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase : public SubsystemBase {
|
||||
public:
|
||||
@ -41,15 +42,14 @@ class AssemblyBase : public SubsystemBase {
|
||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
||||
|
||||
AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth = 8);
|
||||
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
/**
|
||||
* @brief Default periodic handler
|
||||
* @details
|
||||
* This is the default periodic handler which will be called by the SubsystemBase
|
||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||
* of children objects
|
||||
*/
|
||||
virtual void performChildOperation() override;
|
||||
virtual void performChildOperation();
|
||||
|
||||
/**
|
||||
* This function handles changed mode or health states of children
|
||||
* @return
|
||||
*/
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
/**
|
||||
* Core transition handler. The default implementation will only do something if
|
||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||
* from the #doPerformTransition call were executed successfully.
|
||||
*
|
||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||
* determine whether the target mode was reached.
|
||||
*
|
||||
* There is some special handling for certain (internal) modes:
|
||||
* - A second step is necessary. #commandChildren will be performed again
|
||||
* - The device health was overwritten. #commandChildren will be called
|
||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||
*/
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||
|
||||
/**
|
||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||
* change
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||
* variables and then calling the #commandChildren function.
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
virtual bool checkAndHandleRecovery();
|
||||
bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
|
||||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||
|
@ -3,12 +3,17 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
||||
CookieIF* cookie, HasModeTreeChildrenIF& parent,
|
||||
FailureIsolationBase* customFdir, size_t cmdQueueSize)
|
||||
CookieIF* cookie, object_id_t hkDestination,
|
||||
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||
object_id_t parent, FailureIsolationBase* customFdir,
|
||||
size_t cmdQueueSize)
|
||||
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
||||
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
||||
parent(parent),
|
||||
childHandlerFdir(setObjectId) {}
|
||||
parentId(parent),
|
||||
childHandlerFdir(setObjectId) {
|
||||
this->setHkDestination(hkDestination);
|
||||
this->setThermalStateRequestPoolIds(); //TODO
|
||||
}
|
||||
|
||||
ChildHandlerBase::~ChildHandlerBase() {}
|
||||
|
||||
@ -18,5 +23,21 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
return DeviceHandlerBase::connectModeTreeParent(parent);
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
healthHelper.setParentQueue(parentQueue);
|
||||
|
||||
modeHelper.setParentQueue(parentQueue);
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
|
||||
#include <fsfw/subsystem/HasModeTreeChildrenIF.h>
|
||||
|
||||
#include "ChildHandlerFDIR.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
class ChildHandlerBase : public DeviceHandlerBase {
|
||||
public:
|
||||
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
||||
HasModeTreeChildrenIF& parent, FailureIsolationBase* customFdir = nullptr,
|
||||
size_t cmdQueueSize = 20);
|
||||
object_id_t hkDestination, uint32_t thermalStatePoolId,
|
||||
uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT,
|
||||
FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
virtual ~ChildHandlerBase();
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
HasModeTreeChildrenIF& parent;
|
||||
const uint32_t parentId;
|
||||
ChildHandlerFDIR childHandlerFdir;
|
||||
};
|
||||
|
||||
|
@ -49,7 +49,6 @@ class DeviceCommunicationIF {
|
||||
// is this needed if there is no open/close call?
|
||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
||||
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
|
||||
|
||||
virtual ~DeviceCommunicationIF() {}
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
#include "DeviceHandlerBase.h"
|
||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
|
||||
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
#include "fsfw/housekeeping/HousekeepingMessage.h"
|
||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
@ -13,7 +11,6 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||
|
||||
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
@ -24,6 +21,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
|
||||
size_t cmdQueueSize)
|
||||
: SystemObject(setObjectId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
wiretappingMode(OFF),
|
||||
storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
||||
deviceCommunicationId(deviceCommunication),
|
||||
@ -32,19 +31,16 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
modeHelper(this),
|
||||
parameterHelper(this),
|
||||
actionHelper(this, nullptr),
|
||||
poolManager(this, nullptr),
|
||||
datapoolHelper(this),
|
||||
childTransitionFailure(returnvalue::OK),
|
||||
fdirInstance(fdirInstance),
|
||||
defaultFDIRUsed(fdirInstance == nullptr),
|
||||
switchOffWasReported(false),
|
||||
childTransitionDelay(5000),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
transitionSourceMode(_MODE_POWER_DOWN),
|
||||
transitionSourceSubMode(SUBMODE_NONE) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
insertInCommandMap(RAW_COMMAND_ID);
|
||||
cookieInfo.state = COOKIE_UNUSED;
|
||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||
@ -52,13 +48,16 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
||||
"Invalid cookie");
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
this->hkDestination = hkDestination;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; }
|
||||
void DeviceHandlerBase::setThermalStateRequestPoolIds() {}
|
||||
|
||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||
if (comCookie != nullptr) {
|
||||
@ -109,9 +108,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
|
||||
break;
|
||||
case CommunicationAction::GET_READ:
|
||||
doGetRead();
|
||||
/* This will be performed after datasets have been updated by the
|
||||
custom device implementation. */
|
||||
poolManager.performHkOperation();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -124,10 +120,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance =
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
@ -204,6 +196,10 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = datapoolHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = fdirInstance->initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
@ -214,21 +210,22 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = poolManager.initialize(commandQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
// result = poolManager.initialize(commandQueue);
|
||||
// if (result != returnvalue::OK) {
|
||||
// return result;
|
||||
// }
|
||||
|
||||
fillCommandAndReplyMap();
|
||||
|
||||
if (thermalSet != nullptr) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
// Set temperature target state to NON_OP.
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
}
|
||||
}
|
||||
// if (thermalSet != nullptr) { //TODO
|
||||
// // Set temperature target state to NON_OP.
|
||||
// result = thermalSet->read();
|
||||
// if (result == returnvalue::OK) {
|
||||
// thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
// thermalSet->heaterRequest.setValid(true);
|
||||
// thermalSet->commit();
|
||||
// }
|
||||
// }
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -288,10 +285,10 @@ void DeviceHandlerBase::readCommandQueue() {
|
||||
return;
|
||||
}
|
||||
|
||||
result = poolManager.handleHousekeepingMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
// result = poolManager.handleHousekeepingMessage(&command); //TODO
|
||||
// if (result == returnvalue::OK) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
result = handleDeviceHandlerMessage(&command);
|
||||
if (result == returnvalue::OK) {
|
||||
@ -350,6 +347,7 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
callChildStatemachine();
|
||||
break;
|
||||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
@ -363,12 +361,13 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
}
|
||||
} break;
|
||||
case _MODE_WAIT_OFF: {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (powerSwitcher == nullptr) {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
@ -376,7 +375,7 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
setMode(_MODE_SWITCH_IS_OFF);
|
||||
}
|
||||
} break;
|
||||
case MODE_OFF:
|
||||
@ -389,6 +388,9 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
case MODE_NORMAL:
|
||||
case MODE_ERROR_ON:
|
||||
break;
|
||||
case _MODE_SWITCH_IS_OFF:
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
break;
|
||||
default:
|
||||
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
|
||||
setMode(_MODE_POWER_DOWN, 0);
|
||||
@ -413,7 +415,7 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, void* replyDataSet /*TODO*/,
|
||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
|
||||
Countdown* countdown) {
|
||||
// No need to check, as we may try to insert multiple times.
|
||||
@ -428,14 +430,14 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
||||
uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase* dataSet, size_t replyLen,
|
||||
void* dataSet/*TODO*/, size_t replyLen,
|
||||
bool periodic, Countdown* countdown) {
|
||||
DeviceReplyInfo info;
|
||||
info.maxDelayCycles = maxDelayCycles;
|
||||
info.periodic = periodic;
|
||||
info.delayCycles = 0;
|
||||
info.replyLen = replyLen;
|
||||
info.dataSet = dataSet;
|
||||
//info.dataSet = dataSet;
|
||||
info.command = deviceCommandMap.end();
|
||||
info.countdown = countdown;
|
||||
auto resultPair = deviceReplyMap.emplace(replyId, info);
|
||||
@ -528,15 +530,15 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId,
|
||||
LocalPoolDataSetBase* dataSet) {
|
||||
auto replyIter = deviceReplyMap.find(replyId);
|
||||
if (replyIter == deviceReplyMap.end()) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
replyIter->second.dataSet = dataSet;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
// ReturnValue_t DeviceHandlerBase::setReplyDataset(DeviceCommandId_t replyId,
|
||||
// void* dataSet/*TODO*/) {
|
||||
// auto replyIter = deviceReplyMap.find(replyId);
|
||||
// if (replyIter == deviceReplyMap.end()) {
|
||||
// return returnvalue::FAILED;
|
||||
// }
|
||||
// replyIter->second.dataSet = dataSet;
|
||||
// return returnvalue::OK;
|
||||
// }
|
||||
|
||||
void DeviceHandlerBase::callChildStatemachine() {
|
||||
if (mode == _MODE_START_UP) {
|
||||
@ -560,42 +562,27 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
/**
|
||||
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
|
||||
*/
|
||||
if (newMode == MODE_ON and continueToNormal) {
|
||||
continueToNormal = false;
|
||||
// TODO: Check whether the following two lines are okay to do so.
|
||||
transitionSourceMode = MODE_ON;
|
||||
transitionSourceSubMode = newSubmode;
|
||||
mode = _MODE_TO_NORMAL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
// changeHK(mode, submode, false);
|
||||
submode = newSubmode;
|
||||
mode = newMode;
|
||||
modeChanged();
|
||||
setNormalDatapoolEntriesInvalid();
|
||||
if (newMode == MODE_OFF) {
|
||||
disableCommandsAndReplies();
|
||||
}
|
||||
if (!isTransitionalMode()) {
|
||||
// clear this flag when a non-transitional Mode is reached to be safe
|
||||
continueToNormal = false;
|
||||
modeHelper.modeChanged(newMode, newSubmode);
|
||||
announceMode(false);
|
||||
}
|
||||
Clock::getUptime(&timeoutStart);
|
||||
|
||||
if (mode == MODE_OFF and thermalSet != nullptr) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
}
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
}
|
||||
}
|
||||
// if (mode == MODE_OFF and thermalSet != nullptr) { //TODO
|
||||
// ReturnValue_t result = thermalSet->read();
|
||||
// if (result == returnvalue::OK) {
|
||||
// if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
// thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
// }
|
||||
// thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
|
||||
// }
|
||||
// }
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
// changeHK(mode, submode, true);
|
||||
}
|
||||
@ -1066,7 +1053,8 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
|
||||
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
|
||||
}
|
||||
|
||||
// SHOULDDO: throw away DHB and write a new one:
|
||||
// SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the
|
||||
// way, throw away DHB and write a new one:
|
||||
// - Include power and thermal completely, but more modular :-)
|
||||
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
|
||||
// - Modularization?
|
||||
@ -1078,25 +1066,25 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
||||
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Do not check thermal state for MODE_RAW
|
||||
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
|
||||
(thermalSet != nullptr)) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
||||
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
||||
return NON_OP_TEMPERATURE;
|
||||
}
|
||||
}
|
||||
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
|
||||
// ReturnValue_t result = thermalSet->read(); //TODO
|
||||
// if (result == returnvalue::OK) {
|
||||
// if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||
// (not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
||||
// triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
||||
// return NON_OP_TEMPERATURE;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
return isModeCombinationValid(commandedMode, commandedSubmode);
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
|
||||
continueToNormal = false;
|
||||
switch (commandedMode) {
|
||||
case MODE_ON:
|
||||
handleTransitionToOnMode(commandedMode, commandedSubmode);
|
||||
@ -1126,9 +1114,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
|
||||
case MODE_NORMAL:
|
||||
if (mode != MODE_OFF) {
|
||||
setTransition(MODE_NORMAL, commandedSubmode);
|
||||
} else { // mode is off
|
||||
continueToNormal = true;
|
||||
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
|
||||
} else {
|
||||
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1143,14 +1130,15 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
|
||||
// need to call it twice
|
||||
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
|
||||
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
|
||||
if (thermalSet != nullptr) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (thermalSet != nullptr) { //TODO
|
||||
// ReturnValue_t result = thermalSet->read();
|
||||
// if (result == returnvalue::OK) {
|
||||
// if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
// thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
||||
// thermalSet->commit();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
setTransition(MODE_ON, commandedSubmode);
|
||||
}
|
||||
@ -1285,7 +1273,6 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
||||
if (iter->second.command != deviceCommandMap.end()) {
|
||||
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
||||
|
||||
// This may fail, but we'll ignore the fault.
|
||||
if (queueId != NO_COMMANDER) {
|
||||
// This may fail, but we'll ignore the fault.
|
||||
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
||||
@ -1321,22 +1308,23 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) {
|
||||
ActionHelper* DeviceHandlerBase::getActionHelper() { return &actionHelper; }
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::executeAction(Action* action) {
|
||||
ReturnValue_t result = acceptExternalDeviceCommands();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId);
|
||||
DeviceCommandMap::iterator iter = deviceCommandMap.find(action->getId());
|
||||
if (iter == deviceCommandMap.end()) {
|
||||
result = COMMAND_NOT_SUPPORTED;
|
||||
} else if (iter->second.isExecuting) {
|
||||
result = COMMAND_ALREADY_SENT;
|
||||
} else {
|
||||
iter->second.sendReplyTo = commandedBy;
|
||||
result = buildCommandFromCommand(actionId, data, size);
|
||||
result = action->handle();
|
||||
}
|
||||
if (result == returnvalue::OK) {
|
||||
iter->second.sendReplyTo = action->commandedBy;
|
||||
iter->second.isExecuting = true;
|
||||
cookieInfo.pendingCommand = iter;
|
||||
cookieInfo.state = COOKIE_WRITE_READY;
|
||||
@ -1464,54 +1452,25 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||
uint32_t parameter) {}
|
||||
|
||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||
|
||||
void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) {
|
||||
if (thermalStateCfg.has_value()) {
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>());
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>());
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
// In this function, the task handle should be valid if the task
|
||||
// was implemented correctly. We still check to be 1000 % sure :-)
|
||||
if (executingTask != nullptr) {
|
||||
pstIntervalMs = executingTask->getPeriodMs();
|
||||
}
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (thermalStateCfg.has_value()) {
|
||||
ThermalStateCfg& cfg = thermalStateCfg.value();
|
||||
thermalSet = new DeviceHandlerThermalSet(this, cfg);
|
||||
}
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
startTransition(MODE_ON, SUBMODE_NONE);
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase* DeviceHandlerBase::getDataSetHandle(sid_t sid) {
|
||||
auto iter = deviceReplyMap.find(sid.ownerSetId);
|
||||
if (iter != deviceReplyMap.end()) {
|
||||
return iter->second.dataSet;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
object_id_t DeviceHandlerBase::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
void DeviceHandlerBase::setStartUpImmediately() { this->setStartupImmediately = true; }
|
||||
|
||||
dur_millis_t DeviceHandlerBase::getPeriodicOperationFrequency() const { return pstIntervalMs; }
|
||||
|
||||
DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
|
||||
if (cookieInfo.pendingCommand != deviceCommandMap.end()) {
|
||||
return cookieInfo.pendingCommand->first;
|
||||
@ -1520,16 +1479,19 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
|
||||
for (const auto& reply : deviceReplyMap) {
|
||||
if (reply.second.dataSet != nullptr) {
|
||||
PoolReadGuard pg(reply.second.dataSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
reply.second.dataSet->setValidity(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// for (const auto& reply : deviceReplyMap) {
|
||||
// if (reply.second.dataSet != nullptr) {
|
||||
// PoolReadGuard pg(reply.second.dataSet);
|
||||
// if (pg.getReadResult() == returnvalue::OK) {
|
||||
// reply.second.dataSet->setValidity(false, true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
DatapoolHelper* DeviceHandlerBase::getDatapoolHelper() { return &datapoolHelper; }
|
||||
HousekeepingHelper* DeviceHandlerBase::getHousekeepingHelper() { return &datapoolHelper; }
|
||||
|
||||
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName,
|
||||
ReturnValue_t errorCode, const char* errorPrint) {
|
||||
if (errorPrint == nullptr) {
|
||||
@ -1570,8 +1532,6 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const ch
|
||||
}
|
||||
}
|
||||
|
||||
LocalDataPoolManager* DeviceHandlerBase::getHkManagerHandle() { return &poolManager; }
|
||||
|
||||
MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyId) const {
|
||||
auto commandIter = deviceCommandMap.find(replyId);
|
||||
if (commandIter == deviceCommandMap.end()) {
|
||||
@ -1580,51 +1540,4 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
||||
return commandIter->second.sendReplyTo;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
||||
Mode_t DeviceHandlerBase::getMode() { return mode; }
|
||||
|
||||
Submode_t DeviceHandlerBase::getSubmode() { return submode; }
|
||||
|
||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
for (auto& command : deviceCommandMap) {
|
||||
if (command.second.isExecuting) {
|
||||
command.second.isExecuting = false;
|
||||
}
|
||||
}
|
||||
for (auto& reply : deviceReplyMap) {
|
||||
if (!reply.second.periodic) {
|
||||
if (reply.second.countdown != nullptr) {
|
||||
reply.second.countdown->timeOut();
|
||||
} else {
|
||||
reply.second.delayCycles = 0;
|
||||
}
|
||||
reply.second.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& DeviceHandlerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& DeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
||||
ReturnValue_t result) {
|
||||
auto commandIter = deviceCommandMap.find(action);
|
||||
if (commandIter == deviceCommandMap.end()) {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
commandIter->second.isExecuting = false;
|
||||
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
ModeHelper const* DeviceHandlerBase::getModeHelper() const { return &modeHelper; }
|
||||
|
@ -2,17 +2,15 @@
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "DeviceCommunicationIF.h"
|
||||
#include "DeviceHandlerFailureIsolation.h"
|
||||
#include "DeviceHandlerIF.h"
|
||||
#include "DeviceHandlerThermalSet.h"
|
||||
#include "fsfw/action/ActionHelper.h"
|
||||
#include "fsfw/action/HasActionsIF.h"
|
||||
#include "fsfw/datapool/PoolVariableIF.h"
|
||||
#include "fsfw/datapoollocal/HasLocalDataPoolIF.h"
|
||||
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
|
||||
// #include "fsfw/datapool/PoolVariableIF.h"
|
||||
#include "fsfw/datapool/HasDatapoolIF.h"
|
||||
// #include "fsfw/datapoollocal/LocalDataPoolManager.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
@ -22,7 +20,6 @@
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
@ -85,10 +82,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasActionsIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ReceivesParameterMessagesIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public HasDatapoolIF {
|
||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||
|
||||
public:
|
||||
@ -106,51 +101,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
|
||||
/**
|
||||
* extending the modes of DeviceHandler IF for internal state machine
|
||||
*/
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c _MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c _MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c _MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
/**
|
||||
@ -159,12 +109,10 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* The device handler will then take care of creating local pool entries
|
||||
* for the device thermal state and device heating request.
|
||||
* Custom local pool IDs can be assigned as well.
|
||||
* @param thermalStatePoolId
|
||||
* @param thermalRequestPoolId
|
||||
*/
|
||||
void enableThermalModule(ThermalStateCfg cfg);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
void setThermalStateRequestPoolIds(); // TODO
|
||||
/**
|
||||
* @brief Helper function to ease device handler development.
|
||||
* This will instruct the transition to MODE_ON immediately
|
||||
@ -210,7 +158,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @param counter Specifies which Action to perform
|
||||
* @return returnvalue::OK for successful execution
|
||||
*/
|
||||
ReturnValue_t performOperation(uint8_t counter) override;
|
||||
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||
|
||||
/**
|
||||
* @brief Initializes the device handler
|
||||
@ -220,14 +168,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Calls fillCommandAndReplyMap().
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t initialize() override;
|
||||
virtual ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief Intialization steps performed after all tasks have been created.
|
||||
* This function will be called by the executing task.
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DeviceHandlerBase();
|
||||
@ -244,21 +192,20 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual object_id_t getObjectId() const override;
|
||||
|
||||
/**
|
||||
* This is a helper method for classes which are parent nodes in the mode tree.
|
||||
* It registers the passed queue as the destination for mode and health messages.
|
||||
* @param parentQueueId
|
||||
*/
|
||||
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
||||
|
||||
/** @brief Implementation required for HasActionIF */
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t *data, size_t size) override;
|
||||
/** @brief Implementations required for HasActionIF */
|
||||
ActionHelper *getActionHelper() override;
|
||||
ReturnValue_t executeAction(Action *action) override;
|
||||
|
||||
Mode_t getTransitionSourceMode() const;
|
||||
Submode_t getTransitionSourceSubMode() const;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||
virtual HealthState getHealth() override;
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
ModeHelper const *getModeHelper() const override;
|
||||
HealthState getHealth();
|
||||
ReturnValue_t setHealth(HealthState health);
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues,
|
||||
@ -360,35 +307,10 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - Anything else triggers an even with the returnvalue as a parameter
|
||||
*/
|
||||
virtual ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t *id) = 0;
|
||||
/**
|
||||
* @brief Build a device command packet from data supplied by a direct
|
||||
* command (PUS Service 8)
|
||||
* @details
|
||||
* This will be called if an functional command via PUS Service 8 is received and is
|
||||
* the primary interface for functional command instead of #executeAction for users. The
|
||||
* supplied ActionId_t action ID will be converted to a DeviceCommandId_t command ID after
|
||||
* an internal check whether the action ID is a key in the device command map.
|
||||
*
|
||||
* #rawPacket and #rawPacketLen should be set by this method to the packet to be sent.
|
||||
* The existence of the command in the command map and the command size check against 0 are
|
||||
* done by the base class.
|
||||
*
|
||||
* @param deviceCommand The command to build, already checked against deviceCommandMap
|
||||
* @param commandData Pointer to the data from the direct command
|
||||
* @param commandDataLen Length of commandData
|
||||
* @return
|
||||
* - @c returnvalue::OK to send command after #rawPacket and #rawPacketLen
|
||||
* have been set.
|
||||
* - @c HasActionsIF::EXECUTION_COMPLETE to generate a finish reply immediately. This can
|
||||
* be used if no reply is expected
|
||||
* - Anything else triggers an event with the return code as a parameter as well as a
|
||||
* step reply failed with the return code
|
||||
*/
|
||||
virtual ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
|
||||
const uint8_t *commandData,
|
||||
size_t commandDataLen) = 0;
|
||||
|
||||
/* Reply handling */
|
||||
// TODO add way to say, not enough data in buffer, try again later
|
||||
// ComIF needs to decide if buffer will be appended or overwritten
|
||||
/**
|
||||
* @brief Scans a buffer for a valid reply.
|
||||
* @details
|
||||
@ -445,8 +367,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
||||
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
||||
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
|
||||
|
||||
/**
|
||||
* Helper function to get pending command. This is useful for devices
|
||||
* like SPI sensors to identify the last sent command.
|
||||
@ -506,7 +426,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - @c returnvalue::FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase *replyDataSet = nullptr,
|
||||
void *replyDataSet = nullptr,
|
||||
size_t replyLen = 0, bool periodic = false,
|
||||
bool hasDifferentReplyId = false,
|
||||
DeviceCommandId_t replyId = 0,
|
||||
@ -527,7 +447,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - @c returnvalue::FAILED else.
|
||||
*/
|
||||
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
|
||||
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
|
||||
void *dataSet = nullptr, size_t replyLen = 0,
|
||||
bool periodic = false, Countdown *countdown = nullptr);
|
||||
|
||||
/**
|
||||
@ -575,12 +495,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
ReturnValue_t updateReplyMapEntry(DeviceCommandId_t deviceReply, uint16_t delayCycles,
|
||||
uint16_t maxDelayCycles, bool periodic = false);
|
||||
/**
|
||||
* @brief Can be used to set the dataset corresponding to a reply ID manually.
|
||||
* @details
|
||||
* Used by the local data pool manager.
|
||||
*/
|
||||
ReturnValue_t setReplyDataset(DeviceCommandId_t replyId, LocalPoolDataSetBase *dataset);
|
||||
|
||||
/**
|
||||
* Get the time needed to transit from modeFrom to modeTo.
|
||||
@ -600,15 +514,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) = 0;
|
||||
|
||||
/* Functions used by the local data pool manager */
|
||||
/**
|
||||
* This function is used to initialize the local housekeeping pool
|
||||
* entries. The default implementation leaves the pool empty.
|
||||
* @param localDataPoolMap
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) override;
|
||||
|
||||
/**
|
||||
* @brief Set all datapool variables that are update periodically in
|
||||
* normal mode invalid
|
||||
@ -618,16 +524,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* variables inside the dataset to invalid. The user can override this
|
||||
* method optionally.
|
||||
*/
|
||||
virtual void setNormalDatapoolEntriesInvalid();
|
||||
/**
|
||||
* @brief Get the dataset handle for a given SID.
|
||||
* @details
|
||||
* The default implementation will use the deviceCommandMap to look for the corresponding
|
||||
* dataset handle. The user can override this function if this is not desired.
|
||||
* @param sid
|
||||
* @return
|
||||
*/
|
||||
virtual LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;
|
||||
virtual void setNormalDatapoolEntriesInvalid(); //TODO
|
||||
|
||||
DatapoolHelper* getDatapoolHelper() override;
|
||||
HousekeepingHelper* getHousekeepingHelper() override;
|
||||
|
||||
|
||||
/* HasModesIF overrides */
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
@ -707,12 +608,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||
uint32_t parameter = 0);
|
||||
|
||||
/**
|
||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||
* to startup immediately.
|
||||
*/
|
||||
virtual Submode_t getInitialSubmode();
|
||||
|
||||
protected:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||
|
||||
@ -742,18 +637,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
size_t rawPacketLen = 0;
|
||||
|
||||
/**
|
||||
* Get the current mode
|
||||
*
|
||||
* set via setMode()
|
||||
* The mode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
*/
|
||||
Mode_t getMode();
|
||||
|
||||
Mode_t mode;
|
||||
/**
|
||||
* Get the current Submode
|
||||
*
|
||||
* set via setMode()
|
||||
* The submode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
*/
|
||||
Submode_t getSubmode();
|
||||
Submode_t submode;
|
||||
|
||||
/** This is the counter value from performOperation(). */
|
||||
uint8_t pstStep = 0;
|
||||
@ -806,7 +698,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
/* Action helper for HasActionsIF */
|
||||
ActionHelper actionHelper;
|
||||
/* Housekeeping Manager */
|
||||
LocalDataPoolManager poolManager;
|
||||
DatapoolHelper datapoolHelper;
|
||||
|
||||
/**
|
||||
* @brief Information about commands
|
||||
@ -834,18 +726,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* This is used to keep track of pending replies.
|
||||
*/
|
||||
struct DeviceReplyInfo {
|
||||
//! For Command-Reply combinations:
|
||||
//! The maximum number of cycles the handler should wait for a reply
|
||||
//! to this command.
|
||||
//!
|
||||
//! Reply Only:
|
||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
||||
//! definition for delay
|
||||
uint16_t maxDelayCycles;
|
||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
||||
//! For non-periodic replies without a command, this variable is unused.
|
||||
//! A runtime value of 0 means there is no reply is currently expected.
|
||||
//! The currently remaining cycles the handler should wait for a reply,
|
||||
//! 0 means there is no reply expected
|
||||
uint16_t delayCycles;
|
||||
size_t replyLen = 0; //!< Expected size of the reply.
|
||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||
@ -854,7 +739,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! The dataset used to access housekeeping data related to the
|
||||
//! respective device reply. Will point to a dataset held by
|
||||
//! the child handler (if one is specified)
|
||||
LocalPoolDataSetBase *dataSet = nullptr;
|
||||
// LocalPoolDataSetBase *dataSet = nullptr; TODO
|
||||
//! The command that expects this reply.
|
||||
DeviceCommandMap::iterator command;
|
||||
//! Instead of using delayCycles to specify the maximum time to wait for the device reply, it
|
||||
@ -886,7 +771,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! and to send replies.
|
||||
MessageQueueIF *commandQueue = nullptr;
|
||||
|
||||
DeviceHandlerThermalSet *thermalSet = nullptr;
|
||||
void *thermalSet = nullptr; //TODO
|
||||
|
||||
/**
|
||||
* Optional Error code. Can be set in doStartUp(), doShutDown() and
|
||||
@ -901,7 +786,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
/** Pointer to the used FDIR instance. If not provided by child,
|
||||
* default class is instantiated. */
|
||||
FailureIsolationBase *fdirInstance;
|
||||
object_id_t parent = objects::NO_OBJECT;
|
||||
|
||||
//! To correctly delete the default instance.
|
||||
bool defaultFDIRUsed;
|
||||
@ -922,8 +806,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! Object which may be the root cause of an identified fault.
|
||||
static object_id_t defaultFdirParentId;
|
||||
|
||||
std::optional<ThermalStateCfg> thermalStateCfg;
|
||||
|
||||
/**
|
||||
* @brief Send a reply to a received device handler command.
|
||||
*
|
||||
@ -944,8 +826,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
|
||||
*
|
||||
* If the transition is complete, the mode should be set to the target mode,
|
||||
* which can be deduced from the current mode (which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
|
||||
* which can be deduced from the current mode which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
|
||||
*
|
||||
* The intended target submode is already set.
|
||||
* The origin submode can be read in subModeFrom.
|
||||
@ -1006,15 +888,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual void doOnActivity();
|
||||
|
||||
/**
|
||||
* Required for HasLocalDataPoolIF, return a handle to the local pool manager.
|
||||
* @return
|
||||
*/
|
||||
LocalDataPoolManager *getHkManagerHandle() override;
|
||||
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
/**
|
||||
* Returns the delay cycle count of a reply.
|
||||
* A count != 0 indicates that the command is already executed.
|
||||
@ -1106,7 +979,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* by #switches are on
|
||||
* - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by
|
||||
* #switches are off
|
||||
* - @c PowerSwitchIF::returnvalue::FAILED if an error occured
|
||||
* - @c returnvalue::FAILED if an error occured
|
||||
*/
|
||||
ReturnValue_t getStateOfSwitches();
|
||||
|
||||
@ -1194,22 +1067,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t doSendReadHook();
|
||||
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
virtual void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
virtual void doGetRead();
|
||||
|
||||
private:
|
||||
/**
|
||||
* State a cookie is in.
|
||||
@ -1260,18 +1117,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
uint32_t childTransitionDelay;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Mode_t mode;
|
||||
|
||||
/**
|
||||
* The submode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Submode_t submode;
|
||||
|
||||
/**
|
||||
* @brief The mode the current transition originated from
|
||||
*
|
||||
@ -1289,15 +1134,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
Submode_t transitionSourceSubMode;
|
||||
|
||||
/**
|
||||
* used to make the state machine continue from ON to NOMAL when
|
||||
* a Device is commanded to NORMAL in OFF mode
|
||||
*
|
||||
* set in startTransition()
|
||||
* evaluated in setMode() to continue to NORMAL when ON is reached
|
||||
*/
|
||||
bool continueToNormal;
|
||||
|
||||
/**
|
||||
* read the command queue
|
||||
*/
|
||||
@ -1366,6 +1202,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - if the action was successful, the reply timout counter is initialized
|
||||
*/
|
||||
void doGetWrite(void);
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a timeout to detect missed replies.
|
||||
@ -1403,8 +1254,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
|
||||
ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message);
|
||||
|
||||
virtual dur_millis_t getPeriodicOperationFrequency() const override;
|
||||
|
||||
void parseReply(const uint8_t *receivedData, size_t receivedDataLen);
|
||||
|
||||
void handleTransitionToOnMode(Mode_t commandedMode, Submode_t commandedSubmode);
|
||||
@ -1419,11 +1268,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||
const char *errorPrint = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Disables all commands and replies when device is set to MODE_OFF
|
||||
*/
|
||||
void disableCommandsAndReplies();
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||
|
@ -4,15 +4,15 @@
|
||||
#include "fsfw/health/HealthTableIF.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/power/Fuse.h"
|
||||
//#include "fsfw/power/Fuse.h"
|
||||
#include <fsfw/power/PowerSwitchIF.h>
|
||||
#include "fsfw/serviceinterface/ServiceInterfaceStream.h"
|
||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||
|
||||
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth)
|
||||
: FailureIsolationBase(owner, parent, eventQueueDepth),
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent)
|
||||
: FailureIsolationBase(owner, parent),
|
||||
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS,
|
||||
parameterDomainBase++),
|
||||
missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS,
|
||||
@ -30,7 +30,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
// Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
@ -79,16 +78,16 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Fuse::FUSE_WENT_OFF:
|
||||
// Not so good, because PCDU reacted.
|
||||
case Fuse::POWER_ABOVE_HIGH_LIMIT:
|
||||
// Better, because software detected over-current.
|
||||
setFaulty(event->getEvent());
|
||||
break;
|
||||
case Fuse::POWER_BELOW_LOW_LIMIT:
|
||||
// Device might got stuck during boot, retry.
|
||||
handleRecovery(event->getEvent());
|
||||
break;
|
||||
// case Fuse::FUSE_WENT_OFF:
|
||||
// // Not so good, because PCDU reacted.
|
||||
// case Fuse::POWER_ABOVE_HIGH_LIMIT:
|
||||
// // Better, because software detected over-current.
|
||||
// setFaulty(event->getEvent());
|
||||
// break;
|
||||
// case Fuse::POWER_BELOW_LOW_LIMIT:
|
||||
// // Device might got stuck during boot, retry.
|
||||
// handleRecovery(event->getEvent());
|
||||
// break;
|
||||
//****Thermal*****
|
||||
case ThermalComponentIF::COMPONENT_TEMP_LOW:
|
||||
case ThermalComponentIF::COMPONENT_TEMP_HIGH:
|
||||
|
@ -13,8 +13,7 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
|
||||
friend class Heater;
|
||||
|
||||
public:
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth = 10);
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent);
|
||||
~DeviceHandlerFailureIsolation();
|
||||
ReturnValue_t initialize();
|
||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_
|
||||
|
||||
#include "../action/HasActionsIF.h"
|
||||
#include "../datapoollocal/localPoolDefinitions.h"
|
||||
#include "../events/Event.h"
|
||||
#include "../introspection/ClasslessEnum.h"
|
||||
#include "../ipc/MessageQueueSenderIF.h"
|
||||
#include "../modes/HasModesIF.h"
|
||||
#include "DeviceHandlerMessage.h"
|
||||
@ -24,6 +24,9 @@ class DeviceHandlerIF {
|
||||
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
|
||||
static const DeviceCommandId_t NO_COMMAND_ID = -2;
|
||||
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
|
||||
using dh_heater_request_t = uint8_t;
|
||||
using dh_thermal_state_t = int8_t;
|
||||
|
||||
@ -34,23 +37,71 @@ class DeviceHandlerIF {
|
||||
* The mode of the device itself is transparent to the user but related to the mode of the
|
||||
* handler. MODE_ON and MODE_OFF are included in hasModesIF.h
|
||||
*/
|
||||
|
||||
// MODE_ON = 0, //!< The device is powered and ready to perform operations. In this mode, no
|
||||
// commands are sent by the device handler itself, but direct commands van be commanded and will
|
||||
// be interpreted MODE_OFF = 1, //!< The device is powered off. The only command accepted in this
|
||||
// mode is a mode change to on.
|
||||
FSFW_CLASSLESS_ENUM(
|
||||
DeviceHandlerMode, Mode_t,
|
||||
//! The device is powered and ready to perform operations. In this mode, no
|
||||
//! commands are sent by the device handler itself, but direct commands can be
|
||||
//! commanded and will be executed/forwarded to the device
|
||||
//! This is an alias of MODE_ON to have the FSFW_ENUM complete for introspection
|
||||
((DEVICEHANDLER_MODE_ON, HasModesIF::MODE_ON, "On"))
|
||||
//! The device is powered off. The only command accepted in this
|
||||
//! mode is a mode change to on.
|
||||
//! This is an alias of MODE_OFF to have the FSFW_ENUM complete for introspection
|
||||
((DEVICEHANDLER_MODE_OFF, HasModesIF::MODE_OFF, "Off"))
|
||||
//! The device is powered on and the device handler periodically sends
|
||||
//! commands. The commands to be sent are selected by the handler
|
||||
//! according to the submode.
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
((MODE_NORMAL, 2, "Normal"))
|
||||
//! The device is powered on and ready to perform operations. In this mode,
|
||||
//! raw commands can be sent. The device handler will send all replies
|
||||
//! received from the command back to the commanding object.
|
||||
static const Mode_t MODE_RAW = 3;
|
||||
//! received from the command back to the commanding object as raw TM
|
||||
((MODE_RAW, 3, "Raw"))
|
||||
//! The device is shut down but the switch could not be turned off, so the
|
||||
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
|
||||
//! can be commanded, which tries to switch off the device again.
|
||||
static const Mode_t MODE_ERROR_ON = 4;
|
||||
((MODE_ERROR_ON, 4, "Error")))
|
||||
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and is off now. This state is only to do an RMAP
|
||||
//! cycle once more where the doSendRead() function will set the mode to
|
||||
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
||||
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
@ -65,7 +116,6 @@ class DeviceHandlerIF {
|
||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||
|
||||
@ -119,10 +169,10 @@ class DeviceHandlerIF {
|
||||
NOTHING //!< Do nothing.
|
||||
};
|
||||
|
||||
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = sid_t::INVALID_SET_ID - 1;
|
||||
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = 0; // TODO sid_t::INVALID_SET_ID - 1;
|
||||
|
||||
static constexpr lp_id_t DEFAULT_THERMAL_STATE_POOL_ID = localpool::INVALID_LPID - 2;
|
||||
static constexpr lp_id_t DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID = localpool::INVALID_LPID - 1;
|
||||
static constexpr int DEFAULT_THERMAL_STATE_POOL_ID = 0; // TODOlocalpool::INVALID_LPID - 2;
|
||||
static constexpr int DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID = 0; // TODOlocalpool::INVALID_LPID - 1;
|
||||
|
||||
/**
|
||||
* Default Destructor
|
||||
@ -136,10 +186,4 @@ class DeviceHandlerIF {
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
};
|
||||
|
||||
struct ThermalStateCfg {
|
||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID;
|
||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID;
|
||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */
|
||||
|
@ -1,27 +0,0 @@
|
||||
#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_
|
||||
|
||||
#include "../datapoollocal/LocalPoolVariable.h"
|
||||
#include "../datapoollocal/StaticLocalDataSet.h"
|
||||
#include "DeviceHandlerIF.h"
|
||||
|
||||
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
||||
public:
|
||||
DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
|
||||
|
||||
DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)),
|
||||
thermalStatePoolId(cfg.thermalStatePoolId),
|
||||
heaterRequestPoolId(cfg.thermalRequestPoolId) {}
|
||||
|
||||
const lp_id_t thermalStatePoolId;
|
||||
const lp_id_t heaterRequestPoolId;
|
||||
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(sid.objectId, thermalStatePoolId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(sid.objectId, heaterRequestPoolId, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
|
||||
#include "fsfw/action/HasActionsIF.h"
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
#include "../action/HasActionsIF.h"
|
||||
#include "../objectmanager/SystemObjectIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
|
||||
class DeviceTmReportingWrapper : public SerializeIF {
|
||||
public:
|
||||
|
@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
||||
parentQueue(parentQueue),
|
||||
commandQueue(),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
||||
}
|
||||
|
||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
@ -29,10 +27,11 @@ ReturnValue_t HealthDevice::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (parentQueue != MessageQueueIF::NO_QUEUE) {
|
||||
if (parentQueue != 0) {
|
||||
return healthHelper.initialize(parentQueue);
|
||||
}
|
||||
} else {
|
||||
return healthHelper.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); }
|
||||
|
@ -29,8 +29,10 @@ class HealthDevice : public SystemObject, public ExecutableObjectIF, public HasH
|
||||
protected:
|
||||
HealthState lastHealth;
|
||||
|
||||
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t parentQueue;
|
||||
MessageQueueIF* commandQueue;
|
||||
|
||||
public:
|
||||
HealthHelper healthHelper;
|
||||
};
|
||||
|
||||
|
33
src/fsfw/devicehandlers/no_DeviceHandlerThermalSet.h
Normal file
33
src/fsfw/devicehandlers/no_DeviceHandlerThermalSet.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_
|
||||
|
||||
#include "../datapoollocal/LocalPoolVariable.h"
|
||||
#include "../datapoollocal/StaticLocalDataSet.h"
|
||||
#include "DeviceHandlerIF.h"
|
||||
|
||||
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
||||
public:
|
||||
DeviceHandlerThermalSet(
|
||||
HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {}
|
||||
|
||||
DeviceHandlerThermalSet(
|
||||
object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, setId)),
|
||||
thermalStatePoolId(thermalStateId),
|
||||
heaterRequestPoolId(thermalStateRequestId) {}
|
||||
|
||||
const lp_id_t thermalStatePoolId;
|
||||
const lp_id_t heaterRequestPoolId;
|
||||
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(thermalStatePoolId, sid.objectId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(heaterRequestPoolId, sid.objectId, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
@ -39,6 +39,16 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
||||
if (result == returnvalue::OK) {
|
||||
#if FSFW_OBJ_EVENT_TRANSLATION == 1
|
||||
printEvent(&message);
|
||||
#else
|
||||
//TODO
|
||||
sif::debug << "EventManager: ";
|
||||
sif::debug << "0x" << std::hex << std::setw(8) << std::setfill('0') << message.getReporter()
|
||||
<< std::setfill(' ') << std::dec;
|
||||
sif::debug << " reported event with ID " << message.getEventId() << std::endl;
|
||||
sif::debug << std::hex << "P1 Hex: 0x"
|
||||
<< message.getParameter1() << " | P1 Dec: " << std::dec << message.getParameter1()
|
||||
<< std::hex << " | P2 Hex: 0x" << message.getParameter2()
|
||||
<< " | P2 Dec: " << std::dec << message.getParameter2() << std::endl;
|
||||
#endif
|
||||
notifyListeners(&message);
|
||||
}
|
||||
@ -55,9 +65,8 @@ void EventManager::notifyListeners(EventMessage* message) {
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||
<< std::setw(8) << listener.first << " for event 0x" << std::setw(4)
|
||||
<< message->getEventId() << " failed with result 0x" << std::setw(4) << result
|
||||
<< std::setfill(' ') << std::endl;
|
||||
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||
<< result << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||
listener.first, result);
|
||||
|
@ -21,8 +21,6 @@ extern const char* translateEvents(Event event);
|
||||
|
||||
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
||||
public:
|
||||
static const uint16_t DEFAULT_MAX_EVENTS_PER_CYCLE = 80;
|
||||
|
||||
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
|
||||
virtual ~EventManager();
|
||||
|
||||
|
@ -9,9 +9,8 @@
|
||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue =
|
||||
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
FailureIsolationBase::~FailureIsolationBase() {
|
||||
@ -62,12 +61,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||
if (parentIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object "
|
||||
<< "invalid" << std::endl;
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
||||
#else
|
||||
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
||||
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object"
|
||||
<< "invalid." << std::endl;
|
||||
#endif
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
|
@ -12,12 +12,13 @@
|
||||
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
|
||||
public:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
||||
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
||||
//! FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
||||
//! FDIR turns off device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
||||
static const Event FDIR_CHANGED_STATE =
|
||||
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
||||
//!< (oldState) to par1 (newState).
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
||||
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
||||
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
||||
|
||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||
|
@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
parameterWrapper->set(faultCount);
|
||||
break;
|
||||
case ParameterIds::TIMEOUT:
|
||||
parameterWrapper->set(timer.getTimeoutMs());
|
||||
parameterWrapper->set(timer.timeout);
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
|
@ -40,7 +40,6 @@ class HasFileSystemIF {
|
||||
//! [EXPORT] : P1: Can be file system specific error code
|
||||
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
|
||||
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
|
||||
static constexpr ReturnValue_t FILESYSTEM_INACTIVE = MAKE_RETURN_CODE(2);
|
||||
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
|
||||
|
||||
//! [EXPORT] : File system is currently busy
|
||||
@ -74,12 +73,6 @@ class HasFileSystemIF {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
|
||||
// Get the base filename without the full directory path
|
||||
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen,
|
||||
size_t& baseNameLen) = 0;
|
||||
|
||||
virtual bool isDirectory(const char* path) = 0;
|
||||
|
||||
virtual bool fileExists(FilesystemParams params) = 0;
|
||||
|
||||
/**
|
||||
|
@ -18,11 +18,8 @@
|
||||
*/
|
||||
class DleParser {
|
||||
public:
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
|
||||
|
||||
using BufPair = std::pair<uint8_t*, size_t>;
|
||||
|
||||
enum class ContextType { NONE, PACKET_FOUND, ERROR };
|
||||
|
@ -44,12 +44,12 @@ class Type : public SerializeIF {
|
||||
|
||||
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
virtual size_t getSerializedSize() const override;
|
||||
size_t getSerializedSize() const override;
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
private:
|
||||
|
@ -53,9 +53,8 @@ class VectorOperations {
|
||||
mulScalar(vector, 1 / norm(vector, size), normalizedVector, size);
|
||||
}
|
||||
|
||||
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
||||
T max = vector[size - 1];
|
||||
uint8_t foundIndex = size - 1;
|
||||
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||
T max = -1;
|
||||
|
||||
for (; size > 0; size--) {
|
||||
T abs = vector[size - 1];
|
||||
@ -65,35 +64,24 @@ class VectorOperations {
|
||||
if (abs > max) {
|
||||
max = abs;
|
||||
if (index != 0) {
|
||||
foundIndex = size - 1;
|
||||
*index = size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index != nullptr) {
|
||||
*index = foundIndex;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static T maxValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
||||
T max = vector[size - 1];
|
||||
uint8_t foundIndex = size - 1;
|
||||
static T maxValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||
T max = -1;
|
||||
|
||||
for (; size > 0; size--) {
|
||||
if (vector[size - 1] > max) {
|
||||
max = vector[size - 1];
|
||||
if (index != 0) {
|
||||
foundIndex = size - 1;
|
||||
*index = size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index != nullptr) {
|
||||
*index = foundIndex;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp
|
||||
PeriodicHousekeepingHelper.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingHelper.cpp
|
||||
HousekeepingSet.cpp )
|
||||
|
16
src/fsfw/housekeeping/GeneratesHousekeepingIF.h
Normal file
16
src/fsfw/housekeeping/GeneratesHousekeepingIF.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/tmtc/FsfwProtocolHeader.h>
|
||||
|
||||
#include "HousekeepingHelper.h"
|
||||
|
||||
class GeneratesHousekeepingIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::GENERATES_HOUSEKEEPING;
|
||||
|
||||
enum Functions : FsfwProtocolHeader::FunctionType_t { REPORT };
|
||||
|
||||
virtual ~GeneratesHousekeepingIF() = default;
|
||||
|
||||
virtual HousekeepingHelper* getHousekeepingHelper() = 0;
|
||||
};
|
46
src/fsfw/housekeeping/HousekeepingHelper.cpp
Normal file
46
src/fsfw/housekeeping/HousekeepingHelper.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "HousekeepingHelper.h"
|
||||
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
|
||||
#include "GeneratesHousekeepingIF.h"
|
||||
|
||||
HousekeepingHelper::HousekeepingHelper(GeneratesHousekeepingIF* owner) : owner(owner) {}
|
||||
|
||||
ReturnValue_t HousekeepingHelper::initialize() {
|
||||
tmManager = ObjectManager::instance()->get<TmManager>(objects::TM_MANAGER);
|
||||
if (tmManager == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
const HousekeepingSet* HousekeepingHelper::getHousekeepingSet(HousekeepingSetId_t id) {
|
||||
auto iter = housekeepingSets.find(id);
|
||||
if (iter == housekeepingSets.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void HousekeepingHelper::registerSet(HousekeepingSet* set) {
|
||||
auto id = set->getId();
|
||||
housekeepingSets.emplace(id, set);
|
||||
}
|
||||
|
||||
ReturnValue_t HousekeepingHelper::reportHousekeeping(HousekeepingSet* set, const Action* action) {
|
||||
SystemObjectIF* ownerAsObject = dynamic_cast<SystemObjectIF*>(owner);
|
||||
if (ownerAsObject == nullptr) {
|
||||
sif::error << "Duuuuuuuude, what the hell?" << std::endl;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
store_address_t tc;
|
||||
size_t tcOffset = 0;
|
||||
if (action != nullptr) {
|
||||
tc = action->tc;
|
||||
tcOffset = action->tcOffset;
|
||||
}
|
||||
|
||||
return tmManager->sendTmPacket(ownerAsObject->getObjectId(),
|
||||
GeneratesHousekeepingIF::INTERFACE_ID,
|
||||
GeneratesHousekeepingIF::Functions::REPORT, set, tc, tcOffset);
|
||||
}
|
36
src/fsfw/housekeeping/HousekeepingHelper.h
Normal file
36
src/fsfw/housekeeping/HousekeepingHelper.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
#include <fsfw/tmtc/TmManager.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "HousekeepingSet.h"
|
||||
|
||||
class HousekeepingHelper {
|
||||
friend class HousekeepingSet;
|
||||
|
||||
public:
|
||||
HousekeepingHelper(GeneratesHousekeepingIF* owner);
|
||||
~HousekeepingHelper() = default;
|
||||
|
||||
const HousekeepingSet* getHousekeepingSet(HousekeepingSetId_t id);
|
||||
|
||||
const std::map<HousekeepingSetId_t, HousekeepingSet*>* getHousekeepingSets() const {
|
||||
return &housekeepingSets;
|
||||
}
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
GeneratesHousekeepingIF* owner;
|
||||
TmManager* tmManager = nullptr;
|
||||
|
||||
void registerSet(HousekeepingSet* set);
|
||||
|
||||
ReturnValue_t reportHousekeeping(HousekeepingSet* set, const Action* action = nullptr);
|
||||
|
||||
private:
|
||||
std::map<HousekeepingSetId_t, HousekeepingSet*> housekeepingSets;
|
||||
};
|
146
src/fsfw/housekeeping/HousekeepingSet.cpp
Normal file
146
src/fsfw/housekeeping/HousekeepingSet.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include "HousekeepingSet.h"
|
||||
|
||||
#include <fsfw/datapool/DatasetEntryIF.h>
|
||||
|
||||
#include "GeneratesHousekeepingIF.h"
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
HousekeepingSet::HousekeepingSet(GeneratesHousekeepingIF* owner, const EnumIF &id) {
|
||||
if (owner != nullptr) {
|
||||
helper = owner->getHousekeepingHelper();
|
||||
helper->registerSet(this);
|
||||
}
|
||||
this->id = id.getValue();
|
||||
description = id.getDescription();
|
||||
}
|
||||
|
||||
const char* HousekeepingSet::getDescription() const { return description; }
|
||||
#else
|
||||
HousekeepingSet::HousekeepingSet(GeneratesHousekeepingIF* owner, HousekeepingSetId_t id) : id(id) {
|
||||
if (owner != nullptr) {
|
||||
helper = owner->getHousekeepingHelper();
|
||||
helper->registerSet(this);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HousekeepingSet::~HousekeepingSet() {}
|
||||
|
||||
void HousekeepingSet::report(const Action* action) {
|
||||
if (helper != nullptr) {
|
||||
helper->reportHousekeeping(this, action);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t HousekeepingSet::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = SerializeAdapter::serialize(&id, buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
for (auto parameter : parameterList) {
|
||||
result = parameter->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill valid flags
|
||||
size_t index = 0;
|
||||
for (auto parameter : parameterList) {
|
||||
size_t byteIndex = index / 8;
|
||||
size_t bitIndex = index % 8;
|
||||
if (*size + byteIndex > maxSize) { // TODO audition me
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the parameter is a datasetParameter which knows its validity
|
||||
* If not, just set to valid
|
||||
*/
|
||||
DatasetEntryIF* dataSetParameter = dynamic_cast<DatasetEntryIF*>(parameter);
|
||||
if (dataSetParameter != nullptr) {
|
||||
if (dataSetParameter->getValid()) {
|
||||
(*buffer)[byteIndex] |= (1 << bitIndex);
|
||||
} else {
|
||||
(*buffer)[byteIndex] &= ~(1 << bitIndex);
|
||||
}
|
||||
} else {
|
||||
(*buffer)[byteIndex] |= (1 << bitIndex);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
*size += (parameterList.size() - 1) / 8 + 1;
|
||||
if (*size > maxSize) {
|
||||
// how did we end up here
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
}
|
||||
*buffer += (parameterList.size() - 1) / 8 + 1;
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
size_t HousekeepingSet::getSerializedSize() const {
|
||||
size_t size = SerializeAdapter::getSerializedSize(&id);
|
||||
for (auto parameter : parameterList) {
|
||||
size += parameter->getSerializedSize();
|
||||
}
|
||||
const size_t validBytes = (parameterList.size() - 1) / 8 + 1;
|
||||
size += validBytes;
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t HousekeepingSet::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
|
||||
/**
|
||||
* When deserializing, the id needs to be deserialized first, to find the correct class to
|
||||
* deserialize with. Consequentely, it is assumed, that the pointer was already advanced
|
||||
*
|
||||
* SerializeAdapter::deSerialize(&id, buffer, size, streamEndianness); if (result !=
|
||||
*/
|
||||
for (auto parameter : *getParameters()) {
|
||||
result = parameter->deSerialize(buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// read valid flags
|
||||
size_t index = 0;
|
||||
for (auto parameter : parameterList) {
|
||||
size_t byteIndex = index / 8;
|
||||
size_t bitIndex = index % 8;
|
||||
if (byteIndex > *size) { // TODO audition me
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the parameter is a datasetParameter which knows its validity
|
||||
* If not, just set to valid
|
||||
*/
|
||||
DatasetEntryIF* dataSetParameter = dynamic_cast<DatasetEntryIF*>(parameter);
|
||||
if (dataSetParameter != nullptr) {
|
||||
bool valid = ((*buffer)[byteIndex] & (1 << bitIndex)) != 0;
|
||||
dataSetParameter->setValid(valid);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (*size < (parameterList.size() - 1) / 8 + 1) {
|
||||
// how did we end up here
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
*size -= (parameterList.size() - 1) / 8 + 1;
|
||||
*buffer += (parameterList.size() - 1) / 8 + 1;
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
void HousekeepingSet::registerParameter(ParameterIF* parameter) {
|
||||
parameterList.push_back(parameter);
|
||||
}
|
||||
|
||||
std::vector<ParameterIF*> const* HousekeepingSet::getParameters() const { return ¶meterList; }
|
54
src/fsfw/housekeeping/HousekeepingSet.h
Normal file
54
src/fsfw/housekeeping/HousekeepingSet.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/action/Action.h>
|
||||
#include <fsfw/introspection/Enum.h>
|
||||
#include <fsfw/introspection/HasTmTcParametersIF.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class HousekeepingHelper;
|
||||
class GeneratesHousekeepingIF;
|
||||
|
||||
using HousekeepingSetId_t = uint32_t;
|
||||
|
||||
class HousekeepingSet : public HasTmTcParametersIF, public SerializeIF {
|
||||
friend class ParameterIF;
|
||||
|
||||
public:
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
HousekeepingSet(GeneratesHousekeepingIF* owner, const EnumIF &id);
|
||||
#else
|
||||
HousekeepingSet(GeneratesHousekeepingIF* owner, HousekeepingSetId_t id);
|
||||
#endif
|
||||
|
||||
virtual ~HousekeepingSet();
|
||||
|
||||
HousekeepingSetId_t getId() const { return id; }
|
||||
|
||||
virtual void report(const Action* action = nullptr);
|
||||
|
||||
std::vector<ParameterIF*> const* getParameters() const override;
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
const char* getDescription() const;
|
||||
#endif
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
size_t getSerializedSize() const override;
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
protected:
|
||||
HousekeepingHelper* helper = nullptr;
|
||||
HousekeepingSetId_t id;
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
const char* description;
|
||||
#endif
|
||||
std::vector<ParameterIF*> parameterList;
|
||||
|
||||
void registerParameter(ParameterIF* parameter) override;
|
||||
};
|
@ -54,7 +54,7 @@ class HousekeepingSnapshot : public SerializeIF {
|
||||
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr)
|
||||
: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr){};
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
if (timeStamp != nullptr) {
|
||||
/* Endianness will always be MACHINE, so we can simply use memcpy
|
||||
@ -70,14 +70,14 @@ class HousekeepingSnapshot : public SerializeIF {
|
||||
return updateData->serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
|
||||
virtual size_t getSerializedSize() const {
|
||||
size_t getSerializedSize() const {
|
||||
if (updateData == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return timeStampSize + updateData->getSerializedSize();
|
||||
}
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override {
|
||||
if (*size < timeStampSize) {
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
|
@ -3,37 +3,85 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "fsfw/datapoollocal/LocalPoolDataSetBase.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner)
|
||||
: owner(owner) {}
|
||||
|
||||
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
||||
dur_millis_t minimumPeriodicInterval) {
|
||||
dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor) {
|
||||
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
||||
changeCollectionInterval(collectionInterval);
|
||||
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
|
||||
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
||||
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
|
||||
if a HK packet is generated immediately instead of waiting one generation cycle. */
|
||||
internalTickCounter = collectionIntervalTicks;
|
||||
}
|
||||
|
||||
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
|
||||
return collectionInterval;
|
||||
return intervalTicksToSeconds(collectionIntervalTicks);
|
||||
}
|
||||
|
||||
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
||||
if (hkGenerationCd.hasTimedOut()) {
|
||||
hkGenerationCd.resetTimer();
|
||||
if (internalTickCounter >= collectionIntervalTicks) {
|
||||
internalTickCounter = 1;
|
||||
return true;
|
||||
}
|
||||
internalTickCounter++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
|
||||
uint32_t intervalMs = newIntervalSeconds * 1000;
|
||||
if (newIntervalSeconds <= 0) {
|
||||
intervalMs = minimumPeriodicInterval;
|
||||
newIntervalSeconds = static_cast<float>(minimumPeriodicInterval) / 1000.0;
|
||||
uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
|
||||
float collectionIntervalSeconds) {
|
||||
if (owner == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
bool isDiagnostics = owner->isDiagnostics();
|
||||
|
||||
/* Avoid division by zero */
|
||||
if (minimumPeriodicInterval == 0) {
|
||||
if (isDiagnostics) {
|
||||
/* Perform operation each cycle */
|
||||
return 1;
|
||||
} else {
|
||||
return nonDiagIntervalFactor;
|
||||
}
|
||||
} else {
|
||||
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
||||
uint32_t divisor = minimumPeriodicInterval;
|
||||
if (not isDiagnostics) {
|
||||
/* We need to multiply the divisor because non-diagnostics only
|
||||
allow a multiple of the minimum periodic interval */
|
||||
divisor *= nonDiagIntervalFactor;
|
||||
}
|
||||
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
|
||||
if (not isDiagnostics) {
|
||||
/* Now we need to multiply the calculated ticks with the factor as as well
|
||||
because the minimum tick count to generate a non-diagnostic is the factor itself.
|
||||
|
||||
Example calculation for non-diagnostic with
|
||||
0.4 second interval and 0.2 second task interval.
|
||||
Resultant tick count of 5 is equal to operation each second.
|
||||
|
||||
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
|
||||
task interval.
|
||||
Resultant tick count of 10 is equal to operatin every 2 seconds.
|
||||
|
||||
Example calculation for diagnostic with 0.4 second interval and 0.3
|
||||
second task interval. Resulting tick count of 2 is equal to operation
|
||||
every 0.6 seconds. */
|
||||
ticks *= nonDiagIntervalFactor;
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
collectionInterval = newIntervalSeconds;
|
||||
hkGenerationCd.setTimeout(intervalMs);
|
||||
// We want an immediate HK packet at the start, so time out the generation CD immediately.
|
||||
hkGenerationCd.timeOut();
|
||||
}
|
||||
|
||||
float PeriodicHousekeepingHelper::intervalTicksToSeconds(uint32_t collectionInterval) const {
|
||||
/* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
|
||||
the value in seconds */
|
||||
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
|
||||
}
|
||||
|
||||
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
|
||||
collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
class LocalPoolDataSetBase;
|
||||
|
||||
@ -12,7 +11,8 @@ class PeriodicHousekeepingHelper {
|
||||
public:
|
||||
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
||||
|
||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor);
|
||||
|
||||
void changeCollectionInterval(float newInterval);
|
||||
float getCollectionIntervalInSeconds() const;
|
||||
@ -20,10 +20,14 @@ class PeriodicHousekeepingHelper {
|
||||
|
||||
private:
|
||||
LocalPoolDataSetBase* owner = nullptr;
|
||||
Countdown hkGenerationCd;
|
||||
float collectionInterval = 0.0;
|
||||
uint8_t nonDiagIntervalFactor = 0;
|
||||
|
||||
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
||||
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
||||
|
||||
dur_millis_t minimumPeriodicInterval = 0;
|
||||
uint32_t internalTickCounter = 1;
|
||||
uint32_t collectionIntervalTicks = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */
|
||||
|
@ -1,22 +1,22 @@
|
||||
#ifndef FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
|
||||
#define FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
|
||||
|
||||
#include <fsfw/datapoollocal/LocalPoolVariable.h>
|
||||
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
|
||||
#include <cstdint>
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
|
||||
enum errorPoolIds { TM_HITS, QUEUE_HITS, STORE_HITS };
|
||||
|
||||
class InternalErrorDataset : public StaticLocalDataSet<3 * sizeof(uint32_t)> {
|
||||
class InternalErrorDataset {
|
||||
public:
|
||||
static constexpr uint8_t ERROR_SET_ID = 0;
|
||||
|
||||
InternalErrorDataset(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, ERROR_SET_ID) {}
|
||||
InternalErrorDataset(void* owner) {}
|
||||
|
||||
InternalErrorDataset(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, ERROR_SET_ID)) {}
|
||||
InternalErrorDataset(object_id_t objectId) {}
|
||||
|
||||
lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(sid.objectId, TM_HITS, this);
|
||||
lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(sid.objectId, QUEUE_HITS, this);
|
||||
lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(sid.objectId, STORE_HITS, this);
|
||||
// lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(sid.objectId, TM_HITS, this);
|
||||
// lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(sid.objectId, QUEUE_HITS, this);
|
||||
// lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(sid.objectId, STORE_HITS, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ */
|
||||
|
@ -1,28 +1,17 @@
|
||||
#include "fsfw/internalerror/InternalErrorReporter.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
#include "fsfw/ipc/MutexFactory.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
||||
bool enableSetByDefault, float generationFrequency)
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
poolManager(this, commandQueue),
|
||||
enableSetByDefault(enableSetByDefault),
|
||||
generationFrequency(generationFrequency),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
@ -30,12 +19,6 @@ void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
}
|
||||
|
||||
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
CommandMessage message;
|
||||
ReturnValue_t result = commandQueue->receiveMessage(&message);
|
||||
if (result != MessageQueueIF::EMPTY) {
|
||||
poolManager.handleHousekeepingMessage(&message);
|
||||
}
|
||||
|
||||
uint32_t newQueueHits = getAndResetQueueHits();
|
||||
uint32_t newTmHits = getAndResetTmHits();
|
||||
uint32_t newStoreHits = getAndResetStoreHits();
|
||||
@ -45,33 +28,33 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
||||
<< newStoreHits << std::endl;
|
||||
<< "occured!" << std::endl;
|
||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||
#else
|
||||
sif::printDebug(
|
||||
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
||||
"| %lu\n",
|
||||
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
||||
static_cast<unsigned int>(newStoreHits));
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
PoolReadGuard readGuard(&internalErrorDataset);
|
||||
if (readGuard.getReadResult() == returnvalue::OK) {
|
||||
internalErrorDataset.queueHits.value += newQueueHits;
|
||||
internalErrorDataset.storeHits.value += newStoreHits;
|
||||
internalErrorDataset.tmHits.value += newTmHits;
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
|
||||
internalErrorDataset.setChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// {
|
||||
// PoolReadGuard readGuard(&internalErrorDataset);
|
||||
// if (readGuard.getReadResult() == returnvalue::OK) {
|
||||
// internalErrorDataset.queueHits.value += newQueueHits;
|
||||
// internalErrorDataset.storeHits.value += newStoreHits;
|
||||
// internalErrorDataset.tmHits.value += newTmHits;
|
||||
// internalErrorDataset.setValidity(true, true);
|
||||
// if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
|
||||
// internalErrorDataset.setChanged(true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
poolManager.performHkOperation();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
@ -128,46 +111,15 @@ void InternalErrorReporter::incrementStoreHits() {
|
||||
|
||||
object_id_t InternalErrorReporter::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
|
||||
return this->commandQueue->getId();
|
||||
}
|
||||
|
||||
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
|
||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
|
||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
|
||||
poolManager.subscribeForRegularPeriodicPacket(
|
||||
subdp::RegularHkPeriodicParams(internalErrorSid, enableSetByDefault, generationFrequency));
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const {
|
||||
return this->executingTask->getPeriodMs();
|
||||
}
|
||||
|
||||
LocalPoolDataSetBase *InternalErrorReporter::getDataSetHandle(sid_t sid) {
|
||||
return &internalErrorDataset;
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setTaskIF(PeriodicTaskIF *task) { this->executingTask = task; }
|
||||
// MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
|
||||
// return this->commandQueue->getId();
|
||||
// }
|
||||
|
||||
ReturnValue_t InternalErrorReporter::initialize() {
|
||||
ReturnValue_t result = poolManager.initialize(commandQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
|
||||
return poolManager.initializeAfterTaskCreation();
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
||||
this->timeoutType = timeoutType;
|
||||
this->timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
LocalDataPoolManager *InternalErrorReporter::getHkManagerHandle() { return &poolManager; }
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_
|
||||
|
||||
#include "InternalErrorReporterIF.h"
|
||||
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
|
||||
// #include "fsfw/datapoollocal/LocalDataPoolManager.h"
|
||||
#include "fsfw/internalerror/InternalErrorDataset.h"
|
||||
#include "fsfw/ipc/MutexIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
@ -18,11 +18,9 @@
|
||||
*/
|
||||
class InternalErrorReporter : public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public InternalErrorReporterIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public InternalErrorReporterIF {
|
||||
public:
|
||||
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
||||
bool enableSetByDefault, float generationFrequency);
|
||||
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5);
|
||||
|
||||
/**
|
||||
* Enable diagnostic printout. Please note that this feature will
|
||||
@ -36,15 +34,10 @@ class InternalErrorReporter : public SystemObject,
|
||||
virtual ~InternalErrorReporter();
|
||||
|
||||
virtual object_id_t getObjectId() const override;
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
virtual ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) override;
|
||||
virtual dur_millis_t getPeriodicOperationFrequency() const override;
|
||||
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
|
||||
LocalDataPoolManager* getHkManagerHandle() override;
|
||||
//virtual MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
//virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual void queueMessageNotSent() override;
|
||||
@ -53,21 +46,13 @@ class InternalErrorReporter : public SystemObject,
|
||||
|
||||
virtual void storeFull() override;
|
||||
|
||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||
|
||||
protected:
|
||||
MessageQueueIF* commandQueue;
|
||||
LocalDataPoolManager poolManager;
|
||||
|
||||
PeriodicTaskIF* executingTask = nullptr;
|
||||
// MessageQueueIF* commandQueue;
|
||||
|
||||
MutexIF* mutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
bool enableSetByDefault;
|
||||
float generationFrequency;
|
||||
|
||||
sid_t internalErrorSid;
|
||||
InternalErrorDataset internalErrorDataset;
|
||||
|
||||
bool diagnosticPrintout = true;
|
||||
@ -75,9 +60,6 @@ class InternalErrorReporter : public SystemObject,
|
||||
uint32_t queueHits = 0;
|
||||
uint32_t tmHits = 0;
|
||||
uint32_t storeHits = 0;
|
||||
PoolEntry<uint32_t> tmHitsEntry = PoolEntry<uint32_t>();
|
||||
PoolEntry<uint32_t> storeHitsEntry = PoolEntry<uint32_t>();
|
||||
PoolEntry<uint32_t> queueHitsEntry = PoolEntry<uint32_t>();
|
||||
|
||||
uint32_t getAndResetQueueHits();
|
||||
void incrementQueueHits();
|
||||
|
1
src/fsfw/introspection/CMakeLists.txt
Normal file
1
src/fsfw/introspection/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE ParameterTypeSelector.cpp)
|
48
src/fsfw/introspection/ClasslessEnum.h
Normal file
48
src/fsfw/introspection/ClasslessEnum.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
|
||||
// TODO ifdef EnumIF, consistent naming of functions arrays and macros (probably enum values and
|
||||
// descriptions)
|
||||
|
||||
#include "EnumIF.h"
|
||||
#include "EnumCommon.h"
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
|
||||
#define FSFW_CLASSLESS_ENUM(name, type, elements) \
|
||||
enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \
|
||||
\
|
||||
class name : public EnumIF { \
|
||||
public: \
|
||||
enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \
|
||||
name(type value) : value(value) {} \
|
||||
name() : value(-1) {} \
|
||||
name(const name &other) : value(other.value) {} \
|
||||
int64_t getValue() const override { return value; } \
|
||||
operator type() { return value; } \
|
||||
name &operator=(name other) { \
|
||||
value = other.value; \
|
||||
return *this; \
|
||||
} \
|
||||
name &operator=(type value) { \
|
||||
this->value = value; \
|
||||
return *this; \
|
||||
} \
|
||||
CREATE_KEY_ARRAY(elements, type) \
|
||||
VALUE_CHECK(type) \
|
||||
GET_INDEX() \
|
||||
CREATE_DESCRIPTION_ARRAY(elements) \
|
||||
GET_DESCRIPTION_FUNC() \
|
||||
private: \
|
||||
type value; \
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define FSFW_CLASSLESS_ENUM(name, type, elements) \
|
||||
enum name : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) };
|
||||
|
||||
#endif
|
64
src/fsfw/introspection/Enum.h
Normal file
64
src/fsfw/introspection/Enum.h
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/returnvalues/returnvalue.h>
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
|
||||
#include <boost/preprocessor.hpp>
|
||||
|
||||
// TODO ifdef EnumIF, consistent naming of functions arrays and macros (probably enum values and
|
||||
// descriptions)
|
||||
|
||||
#include "EnumIF.h"
|
||||
#include "EnumCommon.h"
|
||||
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
|
||||
#define FSFW_ENUM(name, type, elements) \
|
||||
class name : public EnumIF, public SerializeIF { \
|
||||
public: \
|
||||
enum : type { BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) }; \
|
||||
name(type value) : value(value) {} \
|
||||
name() : value(-1) {} \
|
||||
name(const name &other) : value(other.value) {} \
|
||||
int64_t getValue() const override { return value; } \
|
||||
operator type() { return value; } \
|
||||
name &operator=(name other) { \
|
||||
value = other.value; \
|
||||
return *this; \
|
||||
} \
|
||||
name &operator=(type value) { \
|
||||
this->value = value; \
|
||||
return *this; \
|
||||
} \
|
||||
CREATE_KEY_ARRAY(elements, type) \
|
||||
VALUE_CHECK(type) \
|
||||
GET_INDEX() \
|
||||
CREATE_DESCRIPTION_ARRAY(elements) \
|
||||
GET_DESCRIPTION_FUNC() \
|
||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, \
|
||||
Endianness streamEndianness) const override { \
|
||||
return SerializeAdapter::serialize<>(&value, buffer, size, maxSize, streamEndianness); \
|
||||
} \
|
||||
virtual size_t getSerializedSize() const override { \
|
||||
return SerializeAdapter::getSerializedSize<>(&value); \
|
||||
} \
|
||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, \
|
||||
Endianness streamEndianness) override { \
|
||||
return SerializeAdapter::deSerialize<>(&value, buffer, size, streamEndianness); \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
type value; \
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define FSFW_ENUM(name, type, elements) \
|
||||
enum class name : type { \
|
||||
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(CLEAN_ENUM_ITEM, "", elements)) \
|
||||
};
|
||||
|
||||
|
||||
#endif
|
62
src/fsfw/introspection/EnumCommon.h
Normal file
62
src/fsfw/introspection/EnumCommon.h
Normal file
@ -0,0 +1,62 @@
|
||||
#define CLEAN_ENUM_ITEM(r, data, element) \
|
||||
BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(element), 2), \
|
||||
(BOOST_PP_TUPLE_ELEM(0, element) = BOOST_PP_TUPLE_ELEM(1, element)), \
|
||||
(BOOST_PP_TUPLE_ELEM(0, element)))
|
||||
|
||||
#if defined FSFW_ENUM_VALUE_CHECKS || defined FSFW_INTROSPECTION
|
||||
|
||||
|
||||
#define GET_KEY(r, data, element) (BOOST_PP_TUPLE_ELEM(0, element))
|
||||
#define GET_DESCRIPTION(r, data, element) \
|
||||
BOOST_PP_IF(BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(element), 2), (BOOST_PP_TUPLE_ELEM(2, element)), \
|
||||
(BOOST_PP_TUPLE_ELEM(1, element)))
|
||||
|
||||
#define CREATE_KEY_ARRAY(enum_elements, type) \
|
||||
/*was static constexpr, but clang won't compile that*/ \
|
||||
int64_t elements[BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements))] = { \
|
||||
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements))}; \
|
||||
const int64_t *getElements() const override { return elements; } \
|
||||
size_t getSize() const override { \
|
||||
return BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_KEY, "", enum_elements)); \
|
||||
}
|
||||
#define VALUE_CHECK(type) \
|
||||
bool isValueValid() const override { \
|
||||
for (size_t i = 0; i < sizeof(elements) / sizeof(elements[0]); i++) { \
|
||||
if (value == elements[i]) { \
|
||||
return true; \
|
||||
} \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#ifdef FSFW_INTROSPECTION
|
||||
#define CREATE_DESCRIPTION_ARRAY(elements) \
|
||||
/*was static constexpr, but clang won't compile that*/ \
|
||||
const char \
|
||||
*descriptions[BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_FOR_EACH(GET_DESCRIPTION, "", elements))] = { \
|
||||
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_FOR_EACH(GET_DESCRIPTION, "", elements))}; \
|
||||
const char *const *getDescriptions() const override { return descriptions; }
|
||||
#define GET_INDEX() \
|
||||
size_t getIndex(int64_t value) const override { \
|
||||
for (size_t i = 0; i < sizeof(elements) / sizeof(elements[0]); i++) { \
|
||||
if (value == elements[i]) { \
|
||||
return i; \
|
||||
} \
|
||||
} \
|
||||
return -1; \
|
||||
}
|
||||
#define GET_DESCRIPTION_FUNC() \
|
||||
const char *getDescription() const override { \
|
||||
if (getIndex(value) == static_cast<size_t>(-1)) { \
|
||||
return nullptr; \
|
||||
} else { \
|
||||
return descriptions[getIndex(value)]; \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define GET_INDEX()
|
||||
#define CREATE_DESCRIPTION_ARRAY(elements)
|
||||
#define GET_DESCRIPTION_FUNC()
|
||||
#endif
|
||||
|
||||
#endif
|
16
src/fsfw/introspection/EnumIF.h
Normal file
16
src/fsfw/introspection/EnumIF.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class EnumIF {
|
||||
public:
|
||||
virtual ~EnumIF() {}
|
||||
virtual int64_t getValue() const = 0;
|
||||
virtual bool isValueValid() const = 0;
|
||||
virtual size_t getSize() const = 0;
|
||||
virtual size_t getIndex(int64_t value) const = 0;
|
||||
virtual const int64_t *getElements() const = 0;
|
||||
virtual const char *const *getDescriptions() const = 0;
|
||||
virtual const char *getDescription() const = 0;
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user