1
0
forked from fsfw/fsfw

Compare commits

..

2 Commits

Author SHA1 Message Date
73837856de Do not read me 2023-09-05 12:54:16 +02:00
e73b9ff72c Merge pull request 'v6.0.0' (#729) from development into master
Reviewed-on: fsfw/fsfw#729
2023-02-23 13:42:48 +01:00
187 changed files with 1659 additions and 3448 deletions

3
.gitignore vendored
View File

@ -10,8 +10,5 @@
.settings
.metadata
# VSCode
.vscode
/build*
/cmake-build*

View File

@ -8,42 +8,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
## Fixes
- 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.
- PUS Health Service: Size check for set health command.
Perform operation completion for announce health command.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
- Small tweak for version getter
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
## Added
- add CFDP subsystem ID
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
## Changed
- 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`.
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
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
## Added
- `EventManager`: Add function to print all listeners.
## Changed
- `EventManager`: Queue depth is configurable now
# [v6.0.0] 2023-02-10
## Fixes

View File

@ -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}.36.0
${FSFW_ETL_LIB_MAJOR_VERSION}.28.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}.3.2
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
CACHE STRING "Catch2 library exact version requirement")
# Keep this off by default for now. See PR:

209
README.md
View File

@ -1,208 +1 @@
![FSFW Logo](misc/logo/FSFW_Logo_V3_bw.png)
# Flight Software Framework (FSFW)
The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
automated systems like Satellites.
The initial version of the Flight Software Framework was developed during
the Flying Laptop Project by the University of Stuttgart in cooperation
with Airbus Defence and Space GmbH.
## Quick facts
The framework is designed for systems, which communicate with external devices, perform control loops,
receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore,
a mode and health system provides control over the states of the software and the controlled devices.
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
The FSFW provides abstraction layers for operating systems to provide a uniform operating system
abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
also very useful for developers to implement the same application logic on different operating
systems with a uniform interface.
Currently, the FSFW provides the following OSALs:
- Linux
- Host
- FreeRTOS
- RTEMS
The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile
memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a
ISISPACE IOBC or a Zynq-7020 SoC. The `fsfw` was also successfully run on the
STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active
satellite mission Flying Laptop.
## Getting started
The [Hosted FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted) provides a
good starting point and a demo to see the FSFW capabilities.
It is recommended to get started by building and playing around with the demo application.
There are also other examples provided for all OSALs using the popular embedded platforms
Raspberry Pi, Beagle Bone Black and STM32H7.
Generally, the FSFW is included in a project by providing
a configuration folder, building the static library and linking against it.
There are some functions like `printChar` which are different depending on the target architecture
and need to be implemented by the mission developer.
A template configuration folder was provided and can be copied into the project root to have
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
information about the possible options.
## Prerequisites
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
installed and provided by the build system unless the correction version was installed.
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
the install call:
```cpp
git clone https://github.com/ETLCPP/etl
cd etl
git checkout <currentRecommendedVersion>
mkdir build && cd build
cmake ..
cmake --install .
```
It is recommended to install `20.27.2` or newer for the package version handling of
ETL to work.
## Adding the library
The following steps show how to add and use FSFW components. It is still recommended to
try out the example mentioned above to get started, but the following steps show how to
add and link against the FSFW library in general.
1. Add this repository as a submodule
```sh
git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw
```
2. Add the following directive inside the uppermost `CMakeLists.txt` file of your project
```cmake
add_subdirectory(fsfw)
```
3. Make sure to provide a configuration folder and supply the path to that folder with
the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file.
It is also necessary to provide the `printChar` function. You can find an example
implementation for a hosted build
[here](https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted/src/branch/master/bsp_hosted/utility/printChar.c).
4. Link against the FSFW library
```sh
target_link_libraries(${YourProjectName} PRIVATE fsfw)
```
5. It should now be possible use the FSFW as a static library from the user code.
## Building the unittests
The FSFW also has unittests which use the [Catch2 library](https://github.com/catchorg/Catch2).
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
from your project `CMakeLists.txt` file or from the command line.
You can install the Catch2 library, which prevents the build system to avoid re-downloading
the dependency if the unit tests are completely rebuilt. The current recommended version
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
the `FSFW_CATCH2_LIB_VERSION` variable.
```sh
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout <currentRecommendedVersion>
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install
```
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
If the unittests are built, the library and the tests will be built with coverage information by
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
You can use the following commands inside the `fsfw` folder to set up the build system
```sh
mkdir build-tests && cd build-tests
cmake -DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
```
You can also use `-DFSFW_OSAL=linux` on Linux systems.
Coverage data in HTML format can be generated using the `CodeCoverage`
[CMake module](https://github.com/bilke/cmake-modules/tree/master).
To build the unittests, run them and then generate the coverage data in this format,
the following command can be used inside the build directory after the build system was set up
```sh
cmake --build . -- fsfw-tests_coverage -j
```
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
## Building the documentations
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
instructions provided in [this blogpost](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/). If you
want to do this locally, set up the prerequisites first. This requires a ``python3``
installation as well. Example here is for Ubuntu.
```sh
sudo apt-get install doxygen graphviz
```
And the following Python packages
```sh
python3 -m pip install sphinx breathe
```
You can set up a documentation build system using the following commands
```sh
mkdir build-docs && cd build-docs
cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..
```
Then you can generate the documentation using
```sh
cmake --build . -- Sphinx -j
```
You can find the generated documentation inside the `docs/sphinx` folder inside the build
folder. Simply open the `index.html` in the webbrowser of your choice.
The `helper.py` script located in the script` folder can also be used to create, build
and open the documentation conveniently. Try `helper.py -h for more information.
## Formatting the sources
The formatting is done by the `clang-format` tool. The configuration is contained within the
`.clang-format` file in the repository root. As long as `clang-format` is installed, you
can run the `auto-format.sh` helper script to format all source files consistently. Furthermore cmake-format is required to format CMake files which can be installed with:
````sh
sudo pip install cmakelang
````
## Index
[1. High-level overview](docs/README-highlevel.md#top) <br>
[2. Core components](docs/README-core.md#top) <br>
[3. Configuration](docs/README-config.md#top) <br>
[4. OSAL overview](docs/README-osal.md#top) <br>
[5. PUS services](docs/README-pus.md#top) <br>
[6. Device Handler overview](docs/README-devicehandlers.md#top) <br>
[7. Controller overview](docs/README-controllers.md#top) <br>
[8. Local Data Pools](docs/README-localpools.md#top) <br>
-

View File

@ -97,7 +97,7 @@ pipeline {
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
}
}
dir(BUILDDIR_LINUX) {
dir(BUILDDIR) {
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_LINUX) {
dir(BUILDDIR) {
sshagent(credentials: ['documentation-buildfix']) {
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
}

View File

@ -8,4 +8,4 @@ if(FSFW_ADD_HAL)
add_subdirectory(fsfw_hal)
endif()
#add_subdirectory(fsfw_tests)
add_subdirectory(fsfw_tests)

View File

@ -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,22 +15,20 @@ 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)
@ -38,7 +36,7 @@ add_subdirectory(filesystem)
# Optional
if(FSFW_ADD_MONITORING)
#add_subdirectory(monitoring)
add_subdirectory(monitoring)
endif()
if(FSFW_ADD_PUS)
add_subdirectory(pus)

View File

@ -1,7 +1,6 @@
#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"

View File

@ -1,70 +0,0 @@
#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 &parameterList; }
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;
}

View File

@ -1,64 +0,0 @@
#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;
};

View File

@ -1,6 +1,3 @@
#include <fsfw/serialize/SerializeAdapter.h>
#include <fsfw/tmtc/TmMessage.h>
#include "fsfw/action.h"
#include "fsfw/ipc/MessageQueueSenderIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
@ -13,8 +10,8 @@ ActionHelper::~ActionHelper() = default;
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
prepareExecution(command->getSender(), ActionMessage::getOffset(command),
ActionMessage::getStoreId(command));
ActionId_t currentAction = ActionMessage::getActionId(command);
prepareExecution(command->getSender(), currentAction, ActionMessage::getStoreId(command));
return returnvalue::OK;
} else {
return CommandMessage::UNKNOWN_COMMAND;
@ -26,12 +23,6 @@ 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_);
}
@ -66,89 +57,28 @@ void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t co
void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
MessageQueueIF const* ActionHelper::getQueue() const { return queueToUse; }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
const uint8_t* tcData = nullptr;
size_t tcDataSize = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &tcData, &tcDataSize);
const uint8_t* dataPtr = nullptr;
size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != returnvalue::OK) {
CommandMessage reply;
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, result);
// queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
return;
}
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);
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
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;
}
}
@ -233,11 +163,3 @@ 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; }

View File

@ -1,12 +1,9 @@
#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
*
@ -101,16 +98,6 @@ 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;
@ -119,11 +106,8 @@ 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
@ -131,7 +115,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, size_t offset,
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress);
/**
* @brief Default implementation is empty.

View File

@ -6,14 +6,14 @@ ActionMessage::ActionMessage() = default;
ActionMessage::~ActionMessage() = default;
void ActionMessage::setCommand(CommandMessage* message, size_t offset,
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters) {
message->setCommand(EXECUTE_ACTION);
message->setParameter(offset);
message->setParameter(fid);
message->setParameter2(parameters.raw);
}
size_t ActionMessage::getOffset(const CommandMessage* message) {
ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
return ActionId_t(message->getParameter());
}

View File

@ -27,9 +27,9 @@ class ActionMessage {
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage();
static void setCommand(CommandMessage* message, size_t offset, store_address_t parameters);
static void setCommand(CommandMessage* message, ActionId_t fid, store_address_t parameters);
static size_t getOffset(const CommandMessage* message);
static ActionId_t getActionId(const CommandMessage* message);
static store_address_t getStoreId(const CommandMessage* message);
static void setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,

View File

@ -1,3 +1,3 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE Action.cpp ActionHelper.cpp ActionMessage.cpp
${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp
CommandActionHelper.cpp SimpleActionHelper.cpp)

View File

@ -74,24 +74,24 @@ ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
switch (reply->getCommand()) {
case ActionMessage::COMPLETION_SUCCESS:
commandCount--;
// owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); TODO
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
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;

View File

@ -1,13 +1,11 @@
#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
@ -42,18 +40,12 @@ 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
@ -63,7 +55,8 @@ class HasActionsIF {
* -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not returnvalue::OK Step failure reply will be generated
*/
virtual ReturnValue_t executeAction(Action* action) = 0;
virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) = 0;
};
#endif /* FSFW_ACTION_HASACTIONSIF_H_ */

View File

@ -1,6 +1,4 @@
#include "fsfw/action.h"
#include <fsfw/serialize/SerializeAdapter.h>
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue)
: ActionHelper(setOwner, useThisQueue), isExecuting(false) {}
@ -32,57 +30,25 @@ void SimpleActionHelper::resetHelper() {
lastCommander = 0;
}
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress) {
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) {
CommandMessage reply;
if (isExecuting) {
ipcStore->deleteData(dataAddress);
ActionMessage::setStepReply(&reply, 0 /*TODO*/, 0, HasActionsIF::IS_BUSY);
ActionMessage::setStepReply(&reply, actionId, 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, 0 /*TODO*/, 0, result);
queueToUse->sendMessage(commandedBy, &reply);
ipcStore->deleteData(dataAddress);
return;
}
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();
lastCommander = commandedBy;
lastAction = actionId;
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress);
switch (result) {
case returnvalue::OK:

View File

@ -17,8 +17,8 @@ class SimpleActionHelper : public ActionHelper {
ReturnValue_t reportData(SerializeIF* data);
protected:
virtual void prepareExecution(MessageQueueId_t commandedBy, size_t offset,
store_address_t dataAddress) override;
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress) override;
void resetHelper() override;
private:

View File

@ -1,29 +0,0 @@
#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;
};

View File

@ -51,9 +51,8 @@ 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;

View File

@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
*buffer += 1;
**buffer = pduDataFieldLen & 0x00ff;
*buffer += 1;
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
pduConf.seqNum.getWidth();
*buffer += 1;
*size += 4;
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);

View File

@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
}
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const {
return static_cast<cfdp::WidthInBytes>(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1);
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
}
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
}
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {

View File

@ -23,8 +23,6 @@ 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;

View File

@ -26,8 +26,6 @@ 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;

View File

@ -29,8 +29,6 @@ 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;

View File

@ -12,7 +12,6 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList : public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
"count_t is not large enough to hold MAX_SIZE");
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
private:
T data[MAX_SIZE];

View File

@ -155,8 +155,8 @@ class FixedMap : public SerializeIF {
uint32_t maxSize() const { return theMap.maxSize(); }
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const override {
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
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;
}
size_t getSerializedSize() const override {
virtual size_t getSerializedSize() const {
uint32_t printSize = sizeof(_size);
uint32_t i = 0;
@ -182,8 +182,8 @@ class FixedMap : public SerializeIF {
return printSize;
}
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override {
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) {
ReturnValue_t result =
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
if (this->_size > theMap.maxSize()) {

View File

@ -1 +1,2 @@
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp
ExtendedControllerBase.cpp)

View File

@ -12,10 +12,7 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
mode(MODE_OFF),
submode(SUBMODE_NONE),
modeHelper(this),
healthHelper(this, setObjectId),
actionHelper(this, commandQueue),
datapoolHelper(this),
housekeepingHelper(this) {
healthHelper(this, setObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
}
@ -48,21 +45,6 @@ ReturnValue_t ControllerBase::initialize() {
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;
}
@ -82,12 +64,6 @@ 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;
@ -123,15 +99,6 @@ 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) {

View File

@ -1,15 +1,13 @@
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
#define FSFW_CONTROLLER_CONTROLLERBASE_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>
#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/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
/**
* @brief Generic base class for controller classes
@ -19,14 +17,10 @@
*/
class ControllerBase : public HasModesIF,
public HasHealthIF,
public HasDatapoolIF,
public HasActionsIF,
public ExecutableObjectIF,
public SystemObject {
public:
FSFW_CLASSLESS_ENUM(ControllerModes, Mode_t,
((CONTROLLER_MODE_ON, MODE_ON, "On"))((CONTROLLER_MODE_OFF, MODE_OFF,
"Off"))((MODE_NORMAL, 2, "Normal")))
static const Mode_t MODE_NORMAL = 2;
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
~ControllerBase() override;
@ -45,17 +39,6 @@ class ControllerBase : public HasModesIF,
void setTaskIF(PeriodicTaskIF *task) override;
ReturnValue_t initializeAfterTaskCreation() 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:
/**
* Implemented by child class. Handle command messages which are not
@ -85,12 +68,6 @@ 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.

View File

@ -8,12 +8,11 @@ ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t
ExtendedControllerBase::~ExtendedControllerBase() = default;
ActionHelper *ExtendedControllerBase::getActionHelper() {
return &actionHelper;
}
ReturnValue_t ExtendedControllerBase::executeAction(Action *action) {
return action->handle();
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;
}
object_id_t ExtendedControllerBase::getObjectId() const { return SystemObject::getObjectId(); }

View File

@ -29,10 +29,6 @@ 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;
@ -53,6 +49,10 @@ 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;

View File

@ -1 +1 @@
target_sources(${LIB_FSFW_NAME} PRIVATE Dataset.cpp DatapoolHelper.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp)

View File

@ -1,20 +0,0 @@
#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);
}

View File

@ -1,28 +0,0 @@
#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;
};

View File

@ -1,141 +0,0 @@
#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;
}

View File

@ -1,183 +0,0 @@
#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();
};

View File

@ -1,87 +0,0 @@
#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

View File

@ -1,39 +0,0 @@
#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_ */

View File

@ -1,13 +0,0 @@
#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;
};

View File

@ -0,0 +1,217 @@
#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;
}

View File

@ -0,0 +1,173 @@
#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_ */

View File

@ -0,0 +1,34 @@
#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_ */

View File

@ -0,0 +1,102 @@
#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>;

View File

@ -0,0 +1,140 @@
#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_ */

View File

@ -0,0 +1,28 @@
#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_ */

View File

@ -0,0 +1,62 @@
#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_ */

View File

@ -0,0 +1,27 @@
#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_ */

View File

@ -0,0 +1,30 @@
#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_ */

View File

@ -0,0 +1,16 @@
#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_ */

11
src/fsfw/datapoollocal.h Normal file
View File

@ -0,0 +1,11 @@
#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_ */

View File

@ -6,8 +6,8 @@
#include "AccessLocalPoolF.h"
#include "ProvidesDataPoolSubscriptionIF.h"
#include "fsfw/datapoollocal/DataSetIF.h"
#include "fsfw/datapoollocal/PoolEntry.h"
#include "fsfw/datapool/DataSetIF.h"
#include "fsfw/datapool/PoolEntry.h"
#include "fsfw/housekeeping/AcceptsHkPacketsIF.h"
#include "fsfw/housekeeping/HousekeepingMessage.h"
#include "fsfw/housekeeping/HousekeepingPacketDownlink.h"

View File

@ -87,9 +87,9 @@ class LocalPoolVariable : public LocalPoolObjectBase {
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
SerializeIF::Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* @brief This is a call to read the array's values

View File

@ -98,11 +98,11 @@ class LocalPoolVector : public LocalPoolObjectBase {
T& operator[](size_t i);
const T& operator[](size_t i) const;
ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
SerializeIF::Endianness streamEndiannes) const override;
size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
SerializeIF::Endianness streamEndiannes) const override;
virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override;
/**
* @brief This is a call to read the array's values

View File

@ -4,7 +4,7 @@
#include <cstdint>
#include <map>
#include "PoolEntryIF.h"
#include "../datapool/PoolEntryIF.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../objectmanager/frameworkObjects.h"

View File

@ -12,7 +12,7 @@ ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCo
parentId(parent),
childHandlerFdir(setObjectId) {
this->setHkDestination(hkDestination);
this->setThermalStateRequestPoolIds(); //TODO
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
}
ChildHandlerBase::~ChildHandlerBase() {}

View File

@ -1,9 +1,11 @@
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "DeviceHandlerBase.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/datapoollocal/LocalPoolVariable.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"
@ -31,7 +33,7 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
modeHelper(this),
parameterHelper(this),
actionHelper(this, nullptr),
datapoolHelper(this),
poolManager(this, nullptr),
childTransitionFailure(returnvalue::OK),
fdirInstance(fdirInstance),
defaultFDIRUsed(fdirInstance == nullptr),
@ -57,7 +59,12 @@ void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
this->hkDestination = hkDestination;
}
void DeviceHandlerBase::setThermalStateRequestPoolIds() {}
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId,
lp_id_t heaterRequestPoolId,
uint32_t thermalSetId) {
thermalSet =
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
}
DeviceHandlerBase::~DeviceHandlerBase() {
if (comCookie != nullptr) {
@ -108,6 +115,9 @@ 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;
@ -196,10 +206,6 @@ 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;
@ -210,22 +216,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) { //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();
// }
// }
if (thermalSet != nullptr) {
// 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;
}
@ -285,10 +291,10 @@ void DeviceHandlerBase::readCommandQueue() {
return;
}
// result = poolManager.handleHousekeepingMessage(&command); //TODO
// if (result == returnvalue::OK) {
// return;
// }
result = poolManager.handleHousekeepingMessage(&command);
if (result == returnvalue::OK) {
return;
}
result = handleDeviceHandlerMessage(&command);
if (result == returnvalue::OK) {
@ -415,7 +421,7 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode, Submode_t s
}
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, void* replyDataSet /*TODO*/,
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId,
Countdown* countdown) {
// No need to check, as we may try to insert multiple times.
@ -430,14 +436,14 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
uint16_t maxDelayCycles,
void* dataSet/*TODO*/, size_t replyLen,
LocalPoolDataSetBase* dataSet, 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);
@ -530,15 +536,15 @@ ReturnValue_t DeviceHandlerBase::updatePeriodicReply(bool enable, DeviceCommandI
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;
// }
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;
}
void DeviceHandlerBase::callChildStatemachine() {
if (mode == _MODE_START_UP) {
@ -574,15 +580,15 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
}
Clock::getUptime(&timeoutStart);
// 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);
// }
// }
if (mode == MODE_OFF and thermalSet != nullptr) {
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);
}
@ -1071,14 +1077,14 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
}
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;
// }
// }
ReturnValue_t result = thermalSet->read();
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);
@ -1130,15 +1136,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) { //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();
// }
// }
// }
if (thermalSet != nullptr) {
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);
}
@ -1308,23 +1314,22 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
}
}
ActionHelper* DeviceHandlerBase::getActionHelper() { return &actionHelper; }
ReturnValue_t DeviceHandlerBase::executeAction(Action* action) {
ReturnValue_t DeviceHandlerBase::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result = acceptExternalDeviceCommands();
if (result != returnvalue::OK) {
return result;
}
DeviceCommandMap::iterator iter = deviceCommandMap.find(action->getId());
DeviceCommandMap::iterator iter = deviceCommandMap.find(actionId);
if (iter == deviceCommandMap.end()) {
result = COMMAND_NOT_SUPPORTED;
} else if (iter->second.isExecuting) {
result = COMMAND_ALREADY_SENT;
} else {
result = action->handle();
iter->second.sendReplyTo = commandedBy;
result = buildCommandFromCommand(actionId, data, size);
}
if (result == returnvalue::OK) {
iter->second.sendReplyTo = action->commandedBy;
iter->second.isExecuting = true;
cookieInfo.pendingCommand = iter;
cookieInfo.state = COOKIE_WRITE_READY;
@ -1454,12 +1459,24 @@ void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t obje
void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
if (thermalSet != nullptr) {
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
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 (setStartupImmediately) {
startTransition(MODE_ON, SUBMODE_NONE);
@ -1467,10 +1484,21 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
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;
@ -1479,19 +1507,16 @@ 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) {
@ -1532,6 +1557,8 @@ 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()) {
@ -1539,5 +1566,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
}
return commandIter->second.sendReplyTo;
}
ModeHelper const* DeviceHandlerBase::getModeHelper() const { return &modeHelper; }

View File

@ -6,11 +6,12 @@
#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/datapool/HasDatapoolIF.h"
// #include "fsfw/datapoollocal/LocalDataPoolManager.h"
#include "fsfw/datapool/PoolVariableIF.h"
#include "fsfw/datapoollocal/HasLocalDataPoolIF.h"
#include "fsfw/datapoollocal/LocalDataPoolManager.h"
#include "fsfw/health/HealthHelper.h"
#include "fsfw/ipc/MessageQueueIF.h"
#include "fsfw/modes/HasModesIF.h"
@ -83,7 +84,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
public HasHealthIF,
public HasActionsIF,
public ReceivesParameterMessagesIF,
public HasDatapoolIF {
public HasLocalDataPoolIF {
friend void(Factory::setStaticFrameworkObjectIds)();
public:
@ -112,7 +113,10 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @param thermalStatePoolId
* @param thermalRequestPoolId
*/
void setThermalStateRequestPoolIds(); // TODO
void setThermalStateRequestPoolIds(
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);
/**
* @brief Helper function to ease device handler development.
* This will instruct the transition to MODE_ON immediately
@ -196,14 +200,13 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual void setParentQueue(MessageQueueId_t parentQueueId);
/** @brief Implementations required for HasActionIF */
ActionHelper *getActionHelper() override;
ReturnValue_t executeAction(Action *action) override;
/** @brief Implementation required for HasActionIF */
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
const uint8_t *data, size_t size) override;
Mode_t getTransitionSourceMode() const;
Submode_t getTransitionSourceSubMode() const;
void getMode(Mode_t *mode, Submode_t *submode) override;
ModeHelper const *getModeHelper() const override;
virtual void getMode(Mode_t *mode, Submode_t *submode);
HealthState getHealth();
ReturnValue_t setHealth(HealthState health);
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
@ -307,10 +310,35 @@ 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
@ -426,7 +454,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - @c returnvalue::FAILED else.
*/
ReturnValue_t insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
void *replyDataSet = nullptr,
LocalPoolDataSetBase *replyDataSet = nullptr,
size_t replyLen = 0, bool periodic = false,
bool hasDifferentReplyId = false,
DeviceCommandId_t replyId = 0,
@ -447,7 +475,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - @c returnvalue::FAILED else.
*/
ReturnValue_t insertInReplyMap(DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
void *dataSet = nullptr, size_t replyLen = 0,
LocalPoolDataSetBase *dataSet = nullptr, size_t replyLen = 0,
bool periodic = false, Countdown *countdown = nullptr);
/**
@ -495,6 +523,12 @@ 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.
@ -514,7 +548,15 @@ 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
@ -524,11 +566,16 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* variables inside the dataset to invalid. The user can override this
* method optionally.
*/
virtual void setNormalDatapoolEntriesInvalid(); //TODO
DatapoolHelper* getDatapoolHelper() override;
HousekeepingHelper* getHousekeepingHelper() override;
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;
/* HasModesIF overrides */
virtual void startTransition(Mode_t mode, Submode_t submode) override;
@ -698,7 +745,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/* Action helper for HasActionsIF */
ActionHelper actionHelper;
/* Housekeeping Manager */
DatapoolHelper datapoolHelper;
LocalDataPoolManager poolManager;
/**
* @brief Information about commands
@ -739,7 +786,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; TODO
LocalPoolDataSetBase *dataSet = nullptr;
//! 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
@ -771,7 +818,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
//! and to send replies.
MessageQueueIF *commandQueue = nullptr;
void *thermalSet = nullptr; //TODO
DeviceHandlerThermalSet *thermalSet = nullptr;
/**
* Optional Error code. Can be set in doStartUp(), doShutDown() and
@ -888,6 +935,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual void doOnActivity();
/**
* Required for HasLocalDataPoolIF, return a handle to the local pool manager.
* @return
*/
LocalDataPoolManager *getHkManagerHandle() override;
/**
* Returns the delay cycle count of a reply.
* A count != 0 indicates that the command is already executed.
@ -979,7 +1032,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* by #switches are on
* - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by
* #switches are off
* - @c returnvalue::FAILED if an error occured
* - @c PowerSwitchIF::returnvalue::FAILED if an error occured
*/
ReturnValue_t getStateOfSwitches();
@ -1254,6 +1307,8 @@ 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);

View File

@ -4,8 +4,7 @@
#include "fsfw/health/HealthTableIF.h"
#include "fsfw/modes/HasModesIF.h"
#include "fsfw/objectmanager/ObjectManager.h"
//#include "fsfw/power/Fuse.h"
#include <fsfw/power/PowerSwitchIF.h>
#include "fsfw/power/Fuse.h"
#include "fsfw/serviceinterface/ServiceInterfaceStream.h"
#include "fsfw/thermal/ThermalComponentIF.h"
@ -78,16 +77,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:

View File

@ -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"
@ -37,30 +37,23 @@ 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
*/
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.
((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 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.
((MODE_ERROR_ON, 4, "Error")))
// 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.
//! 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;
//! 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;
//! 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;
//! 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.
@ -169,10 +162,10 @@ class DeviceHandlerIF {
NOTHING //!< Do nothing.
};
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = 0; // TODO sid_t::INVALID_SET_ID - 1;
static constexpr uint32_t DEFAULT_THERMAL_SET_ID = sid_t::INVALID_SET_ID - 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;
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;
/**
* Default Destructor

View File

@ -15,12 +15,11 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
EventManager::EventManager(object_id_t setObjectId, uint32_t eventQueueDepth)
EventManager::EventManager(object_id_t setObjectId)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
eventReportQueue = QueueFactory::instance()->createMessageQueue(
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
EventMessage::EVENT_MESSAGE_SIZE);
}
EventManager::~EventManager() {
@ -39,16 +38,6 @@ 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);
}
@ -58,20 +47,9 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
void EventManager::notifyListeners(EventMessage* message) {
lockMutex();
for (auto& listener : listenerList) {
if (listener.second.match(message)) {
ReturnValue_t result =
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
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 << " 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);
#endif
}
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
if (iter->second.match(message)) {
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
}
}
unlockMutex();
@ -222,19 +200,4 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
}
}
void EventManager::printListeners() {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
for (auto& listener : listenerList) {
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
}
sif::info << std::dec << std::setfill(' ');
#else
sif::printInfo("Event manager listener MQ IDs:\n");
for (auto& listener : listenerList) {
sif::printInfo("0x%08x\n", listener.first);
}
#endif
}
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */

View File

@ -21,7 +21,9 @@ extern const char* translateEvents(Event event);
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
public:
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
static const uint16_t MAX_EVENTS_PER_CYCLE = 80;
EventManager(object_id_t setObjectId);
virtual ~EventManager();
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
@ -42,7 +44,6 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
bool reporterInverted = false);
ReturnValue_t performOperation(uint8_t opCode);
void printListeners();
protected:
MessageQueueIF* eventReportQueue = nullptr;

View File

@ -10,7 +10,7 @@ enum : uint8_t {
CDH = 28,
TCS_1 = 59,
PCDU_1 = 42,
POWER_SWITCH_IF = 43,
PCDU_2 = 43,
HEATER = 50,
T_SENSORS = 52,
FDIR = 70,
@ -33,7 +33,6 @@ enum : uint8_t {
PUS_SERVICE_23 = 103,
MGM_LIS3MDL = 106,
MGM_RM3100 = 107,
CFDP = 108,
FW_SUBSYSTEM_ID_RANGE
};

View File

@ -44,13 +44,13 @@ class Type : public SerializeIF {
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override;
size_t getSerializedSize() const override;
virtual size_t getSerializedSize() const override;
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override;
private:
ActualType_t actualType;

View File

@ -1,2 +1,2 @@
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingHelper.cpp
HousekeepingSet.cpp )
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp
PeriodicHousekeepingHelper.cpp)

View File

@ -1,16 +0,0 @@
#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;
};

View File

@ -1,46 +0,0 @@
#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);
}

View File

@ -1,36 +0,0 @@
#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;
};

View File

@ -1,146 +0,0 @@
#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 &parameterList; }

View File

@ -1,54 +0,0 @@
#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;
};

View File

@ -54,8 +54,8 @@ class HousekeepingSnapshot : public SerializeIF {
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr)
: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr){};
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) const {
virtual 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
here. */
@ -70,15 +70,15 @@ class HousekeepingSnapshot : public SerializeIF {
return updateData->serialize(buffer, size, maxSize, streamEndianness);
}
size_t getSerializedSize() const {
virtual size_t getSerializedSize() const {
if (updateData == nullptr) {
return 0;
}
return timeStampSize + updateData->getSerializedSize();
}
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override {
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override {
if (*size < timeStampSize) {
return SerializeIF::STREAM_TOO_SHORT;
}

View File

@ -1,22 +1,22 @@
#ifndef FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#define FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#include <cstdint>
#include <fsfw/objectmanager/SystemObjectIF.h>
#include <fsfw/datapoollocal/LocalPoolVariable.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
enum errorPoolIds { TM_HITS, QUEUE_HITS, STORE_HITS };
class InternalErrorDataset {
class InternalErrorDataset : public StaticLocalDataSet<3 * sizeof(uint32_t)> {
public:
static constexpr uint8_t ERROR_SET_ID = 0;
InternalErrorDataset(void* owner) {}
InternalErrorDataset(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, ERROR_SET_ID) {}
InternalErrorDataset(object_id_t objectId) {}
InternalErrorDataset(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, ERROR_SET_ID)) {}
// 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_ */

Some files were not shown because too many files have changed in this diff Show More