Merge remote-tracking branch 'upstream/development' into mueller/master

This commit is contained in:
Robin Müller 2022-02-14 22:17:14 +01:00
commit 67a79c505a
No known key found for this signature in database
GPG Key ID: 71B58F8A3CDFA9AC
28 changed files with 603 additions and 65 deletions

View File

@ -1,4 +1,214 @@
# Changed from ASTP 1.1.0 to 1.2.0 Change Log
=======
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased]
# [v4.0.0]
## Additions
- CFDP Packet Stack and related tests added. It also refactors the existing TMTC infastructure to
allow sending of CFDP packets to the CCSDS handlers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/528
- added virtual function to print datasets
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/544
- doSendRead Hook
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/545
- Dockumentation for DHB
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/551
### HAL additions
- Linux Command Executor, which can execute shell commands in blocking and non-blocking mode
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/536
- uio Mapper
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/543
## Changes
- Applied the `clang-format` auto-formatter to all source code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/534
- Updated Catch2 to v3.0.0-preview4
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/538
- Changed CI to use prebuilt docker image
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/549
## Bugfix
- CMake fixes in PR https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/533 , was problematic
if the uppermost user `CMakeLists.txt` did not have the include paths set up properly, which
could lead to compile errors that `#include "fsfw/FSFW.h"` was not found.
- Fix for build regression in Catch2 v3.0.0-preview4
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/548
- Fix in unittest which failed on CI
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/552
- Fix in helper script
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/553
## API Changes
- Aforementioned changes to existing TMTC stack
## Known bugs
-
# [v3.0.1]
## API Changes
*
## Bugfixes
* Version number was not updated for v3.0.0 #542
## Enhancement
*
## Known bugs
*
# [v3.0.0]
## API Changes
#### TCP Socket Changes
* Keep Open TCP Implementation #496
* The socket will now kept open after disconnect. This allows reconnecting.
* Only one connection is allowed
* No internal influence but clients need to change their Code.
### GPIO IF
* Add feature to open GPIO by line name #506
### Bitutil
* Unittests for Op Divider and Bitutility #510
### Filesystem IF changed
* Filesystem Base Interface: Use IF instead of void pointer #511
### STM32
* STM32 SPI Updates #518
## Bugfixes
* Small bugfix for LIS3 handler #504
* Spelling fixed for function names #509
* CMakeLists fixes #517
* Out of bound reads and writes in unittests #519
* Bug in TmPacketStoredPusC (#478)
* Windows ifdef fixed #529
## Enhancement
* FSFW.h.in more default values #491
* Minor updates for PUS services #498
* HasReturnvaluesIF naming for parameter #499
* Tests can now be built as part of FSFW and versioning moved to CMake #500
* Added integration test code #508
* More printouts for rejected TC packets #505
* Arrayprinter format improvements #514
* Adding code for CI with docker and jenkins #520
* Added new function in SerializeAdapter #513
* Enables simple deSerialize if you keep track of the buffer position yourself
* `` static ReturnValue_t deSerialize(T *object, const uint8_t* buffer,
size_t* deserSize, SerializeIF::Endianness streamEndianness) ``
* Unittest helper scripts has a new Parameter to open the coverage html in the webrowser #525
* ``'-o', '--open', Open coverage data in webbrowser``
* Documentation updated. Sphinx Documentation can now be build with python script #526
## Known bugs
* Version number was not updated for v3.0.0 #542
All Pull Requests:
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/19
# [v2.0.0]
## API Changes
### File Structure changed to fit more common structure
* See pull request (#445)
* HAL is now part of the main project
* **See Instructions below:**
#### Instruction how to update existing / user code
* Changes in `#include`:
* Rename `internalError` in includes to `internalerror`
* Rename `fsfw/hal` to `fsfw_hal`
* Rename `fsfw/tests` to `fsfw_tests`
* Rename `osal/FreeRTOS` to `osal/freertos`
* Changes in `CMakeLists.txt`:
* Rename `OS_FSFW` to `FSFW_OSAL`
* Changes in `DleEncoder.cpp`
* Create an instance of the `DleEncoder` first before calling the `encode` and `decode` functions
### Removed osal/linux/Timer (#486)
* Was redundant to timemanager/Countdown
#### Instruction how to update existing / user code
* Use timemanager/Countdown instead
## Bugfixes
### TM Stack
* Increased TM stack robustness by introducing `nullptr` checks and more printouts (#483)
#### Host OSAL / FreeRTOS
* QueueMapManager Bugfix (NO_QUEUE was used as MessageQueueId) (#444)
#### Events
* Event output is now consistent (#447)
#### DLE Encoder
* Fixed possible out of bounds access in DLE Encoder (#492)
## Enhancment
* HAL as major new feature, also includes three MEMS devicehandlers as part of #481
* Linux HAL updates (#456)
* FreeRTOS Header cleaning update and Cmake tweaks (#442)
* Printer updates (#453)
* New returnvalue for for empty PST (#485)
* TMTC Bridge: Increase limit of packets stored (#484)
## Known bugs
* Bug in TmPacketStoredPusC (#478)
All Pull Requests:
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/5
# [v1.2.0]
## API Changes ## API Changes
@ -27,7 +237,7 @@
- See API changes chapter. This change will keep the internal API consistent in the future - See API changes chapter. This change will keep the internal API consistent in the future
# Changes from ASTP 1.0.0 to 1.1.0 # [v1.1.0]
## API Changes ## API Changes

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
set(FSFW_VERSION 3) set(FSFW_VERSION 4)
set(FSFW_SUBVERSION 0) set(FSFW_SUBVERSION 0)
set(FSFW_REVISION 0) set(FSFW_REVISION 0)
@ -60,6 +60,8 @@ if(FSFW_BUILD_UNITTESTS)
) )
FetchContent_MakeAvailable(Catch2) FetchContent_MakeAvailable(Catch2)
#fixes regression -preview4, to be confirmed in later releases
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif() endif()
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg) set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)

View File

@ -107,6 +107,42 @@ cmake --build . -- fsfw-tests_coverage -j
The `coverage.py` script located in the `script` folder can also be used to do this conveniently. 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 . -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 ## Formatting the sources
The formatting is done by the `clang-format` tool. The configuration is contained within the The formatting is done by the `clang-format` tool. The configuration is contained within the

View File

@ -6,9 +6,3 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise #tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
RUN git clone https://github.com/catchorg/Catch2.git && \
cd Catch2 && \
git checkout v3.0.0-preview4 && \
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
cmake --build build/ --target install

View File

@ -3,13 +3,7 @@ pipeline {
BUILDDIR = 'build-tests' BUILDDIR = 'build-tests'
} }
agent { agent {
dockerfile { docker { image 'fsfw-ci:d1'}
dir 'automation'
//force docker to redownload base image and rebuild all steps instead of caching them
//this way, we always get an up to date docker image one each build
additionalBuildArgs '--no-cache --pull'
reuseNode true
}
} }
stages { stages {
stage('Clean') { stage('Clean') {

View File

@ -1,3 +1,110 @@
.. _dhb-prim-doc:
Device Handlers Device Handlers
================== ==================
Device handler components represent, control and monitor equipment, for example sensors or actuators
of a spacecraft or the payload.
Most device handlers have the same common functionality or
requirements, which are fulfilled by implementing certain interfaces:
- The handler/device needs to be commandable: :cpp:class:`HasActionsIF`
- The handler needs to communicate with the physical device via a dedicated
communication bus, for example SpaceWire, UART or SPI: :cpp:class:`DeviceCommunicationIF`
- The handler has housekeeping data which has to be exposed to the operator and/or other software
components: :cpp:class:`HasLocalDataPoolIF`
- The handler has configurable parameters: :cpp:class:`ReceivesParameterMessagesIF` which
also implements :cpp:class:`HasParametersIF`
- The handler has health states, for example to indicate a broken device:
:cpp:class:`HasHealthIF`
- The handler has modes. For example there are the core modes `MODE_ON`, `MODE_OFF`
and `MODE_NORMAL` provided by the FSFW. `MODE_ON` means that a device is physically powered
but that it is not periodically polling data from the
physical device, `MODE_NORMAL` means that it is able to do that: :cpp:class:`HasModesIF`
The device handler base therefore provides abstractions for a lot of common
functionality, which can potentially avoid high amounts or logic and code duplication.
Template Device Handler Base File
----------------------------------
This is an example template device handler header file with all necessary
functions implemented:
.. code-block:: cpp
#ifndef __TESTDEVICEHANDLER_H_
#define __TESTDEVICEHANDLER_H_
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
class TestDeviceHandler: DeviceHandlerBase {
public:
TestDeviceHandler(object_id_t objectId, object_id_t comIF, CookieIF* cookie);
private:
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override;
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t* id) override;
void fillCommandAndReplyMap() override;
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData,
size_t commandDataLen) override;
ReturnValue_t scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId,
size_t* foundLen) override;
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) override;
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
};
#endif /* __TESTDEVICEHANDLER_H_ */
and the respective source file with sensible default return values:
.. code-block:: cpp
#include "TestDeviceHandler.h"
TestDeviceHandler::TestDeviceHandler(object_id_t objectId, object_id_t comIF, CookieIF* cookie)
: DeviceHandlerBase(objectId, comIF, cookie) {}
void TestDeviceHandler::doStartUp() {}
void TestDeviceHandler::doShutDown() {}
ReturnValue_t TestDeviceHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TestDeviceHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
return HasReturnvaluesIF::RETURN_OK;
}
void TestDeviceHandler::fillCommandAndReplyMap() {}
ReturnValue_t TestDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
const uint8_t* commandData,
size_t commandDataLen) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TestDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize,
DeviceCommandId_t* foundId, size_t* foundLen) {
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TestDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
const uint8_t* packet) {
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t TestDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) {
return 10000;
}
ReturnValue_t TestDeviceHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) {
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -90,8 +90,21 @@ Building the documentation
---------------------------- ----------------------------
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the 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/>`_. You can set up a instructions provided in `this blogpost <https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/>`_. If you
documentation build system using the following commands want to do this locally, set up the prerequisites first. This requires a ``python3``
installation as well. Example here is for Ubuntu.
.. code-block:: console
sudo apt-get install doxygen graphviz
And the following Python packages
.. code-block:: console
python3 -m pip install sphinx breathe
You can set up a documentation build system using the following commands
.. code-block:: bash .. code-block:: bash
@ -110,6 +123,14 @@ 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 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. and open the documentation conveniently. Try ``helper.py -h`` for more information.
Formatting the source
-----------------------
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 ``apply-clang-format.sh`` helper script to format all source files consistently.
.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted .. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted
.. _`Catch2 library`: https://github.com/catchorg/Catch2 .. _`Catch2 library`: https://github.com/catchorg/Catch2
.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master .. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master

View File

@ -118,7 +118,7 @@ The DH has mechanisms to monitor the communication with the physical device whic
for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``. for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``.
A standard FDIR component for the DH will be created automatically but can A standard FDIR component for the DH will be created automatically but can
be overwritten by the user. More information on DeviceHandlers can be found in the be overwritten by the user. More information on DeviceHandlers can be found in the
related [documentation section](doc/README-devicehandlers.md#top). related :ref:`documentation section <dhb-prim-doc>`.
Modes and Health Modes and Health
-------------------- --------------------

View File

@ -14,3 +14,5 @@ if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
add_subdirectory(i2c) add_subdirectory(i2c)
add_subdirectory(uart) add_subdirectory(uart)
endif() endif()
add_subdirectory(uio)

View File

@ -0,0 +1,3 @@
target_sources(${LIB_FSFW_NAME} PUBLIC
UioMapper.cpp
)

View File

@ -0,0 +1,86 @@
#include "UioMapper.h"
#include <fcntl.h>
#include <unistd.h>
#include <filesystem>
#include <fstream>
#include <sstream>
#include "fsfw/serviceinterface.h"
const char UioMapper::UIO_PATH_PREFIX[] = "/sys/class/uio/";
const char UioMapper::MAP_SUBSTR[] = "/maps/map";
const char UioMapper::SIZE_FILE_PATH[] = "/size";
UioMapper::UioMapper(std::string uioFile, int mapNum) : uioFile(uioFile), mapNum(mapNum) {}
UioMapper::~UioMapper() {}
ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permissions) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
int fd = open(uioFile.c_str(), O_RDWR);
if (fd < 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PtmeAxiConfig::initialize: Invalid UIO device file" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
size_t size = 0;
result = getMapSize(&size);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*address = static_cast<uint32_t*>(
mmap(NULL, size, static_cast<int>(permissions), MAP_SHARED, fd, mapNum * getpagesize()));
if (*address == MAP_FAILED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UioMapper::getMappedAdress: Failed to map physical address of uio device "
<< uioFile.c_str() << " and map" << static_cast<int>(mapNum) << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t UioMapper::getMapSize(size_t* size) {
std::stringstream namestream;
namestream << UIO_PATH_PREFIX << uioFile.substr(5, std::string::npos) << MAP_SUBSTR << mapNum
<< SIZE_FILE_PATH;
FILE* fp;
fp = fopen(namestream.str().c_str(), "r");
if (fp == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UioMapper::getMapSize: Failed to open file " << namestream.str() << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
char hexstring[SIZE_HEX_STRING] = "";
int items = fscanf(fp, "%s", hexstring);
if (items != 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UioMapper::getMapSize: Failed with error code " << errno
<< " to read size "
"string from file "
<< namestream.str() << std::endl;
#endif
fclose(fp);
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t sizeTmp = 0;
items = sscanf(hexstring, "%x", &sizeTmp);
if (size != nullptr) {
*size = sizeTmp;
}
if (items != 1) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "UioMapper::getMapSize: Failed with error code " << errno << "to convert "
<< "size of map" << mapNum << " to integer" << std::endl;
#endif
fclose(fp);
return HasReturnvaluesIF::RETURN_FAILED;
}
fclose(fp);
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,58 @@
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_
#include <sys/mman.h>
#include <string>
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
/**
* @brief Class to help opening uio device files and mapping the physical addresses into the user
* address space.
*
* @author J. Meier
*/
class UioMapper {
public:
enum class Permissions : int {
READ_ONLY = PROT_READ,
WRITE_ONLY = PROT_WRITE,
READ_WRITE = PROT_READ | PROT_WRITE
};
/**
* @brief Constructor
*
* @param uioFile The device file of the uiO to open
* @param uioMap Number of memory map. Most UIO drivers have only one map which has than 0.
*/
UioMapper(std::string uioFile, int mapNum = 0);
virtual ~UioMapper();
/**
* @brief Maps the physical address into user address space and returns the mapped address
*
* @address The mapped user space address
* @permissions Specifies the read/write permissions of the address region
*/
ReturnValue_t getMappedAdress(uint32_t** address, Permissions permissions);
private:
static const char UIO_PATH_PREFIX[];
static const char MAP_SUBSTR[];
static const char SIZE_FILE_PATH[];
static constexpr int SIZE_HEX_STRING = 10;
std::string uioFile;
int mapNum = 0;
/**
* @brief Reads the map size from the associated sysfs size file
*
* @param size The read map size
*/
ReturnValue_t getMapSize(size_t* size);
};
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_ */

View File

@ -143,7 +143,10 @@ def handle_tests_type(args, build_dir_list: list):
if which("valgrind") is None: if which("valgrind") is None:
print("Please install valgrind first") print("Please install valgrind first")
sys.exit(1) sys.exit(1)
os.chdir(UNITTEST_FOLDER_NAME) if os.path.split(os.getcwd())[1] != UNITTEST_FOLDER_NAME:
# If we are in a different directory we try to switch into it but
# this might fail
os.chdir(UNITTEST_FOLDER_NAME)
os.system("valgrind --leak-check=full ./fsfw-tests") os.system("valgrind --leak-check=full ./fsfw-tests")
os.chdir("..") os.chdir("..")

View File

@ -30,7 +30,7 @@ class DataLinkLayer : public CCSDSReturnValuesIF {
//! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0 //! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO); static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO);
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board // static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board
//detected that either bit lock or RF available or both are lost. No parameters. // detected that either bit lock or RF available or both are lost. No parameters.
//! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC //! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW); static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW);
/** /**

View File

@ -30,9 +30,9 @@ ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame)
mapChannelIterator iter = mapChannels.find(mapId); mapChannelIterator iter = mapChannels.find(mapId);
if (iter == mapChannels.end()) { if (iter == mapChannels.end()) {
// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int) // error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int)
//channelId // channelId
// << ": MapChannel " << (int) mapId << std::dec << " not found." << // << ": MapChannel " << (int) mapId << std::dec << " not found." <<
//std::endl; // std::endl;
return VC_NOT_FOUND; return VC_NOT_FOUND;
} else { } else {
return (iter->second)->extractPackets(frame); return (iter->second)->extractPackets(frame);

View File

@ -291,3 +291,5 @@ float LocalPoolDataSetBase::getCollectionInterval() const {
return 0.0; return 0.0;
} }
} }
void LocalPoolDataSetBase::printSet() { return; }

View File

@ -171,6 +171,11 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
*/ */
float getCollectionInterval() const; float getCollectionInterval() const;
/**
* @brief Can be overwritten by a specific implementation of a dataset to print the set.
*/
virtual void printSet();
protected: protected:
sid_t sid; sid_t sid;
//! This mutex is used if the data is created by one object only. //! This mutex is used if the data is created by one object only.

View File

@ -665,6 +665,11 @@ void DeviceHandlerBase::doGetWrite() {
void DeviceHandlerBase::doSendRead() { void DeviceHandlerBase::doSendRead() {
ReturnValue_t result; ReturnValue_t result;
result = doSendReadHook();
if (result != RETURN_OK) {
return;
}
size_t replyLen = 0; size_t replyLen = 0;
if (cookieInfo.pendingCommand != deviceCommandMap.end()) { if (cookieInfo.pendingCommand != deviceCommandMap.end()) {
replyLen = getNextReplyLength(cookieInfo.pendingCommand->first); replyLen = getNextReplyLength(cookieInfo.pendingCommand->first);
@ -920,6 +925,8 @@ void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) {
} }
} }
ReturnValue_t DeviceHandlerBase::doSendReadHook() { return RETURN_OK; }
ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t** switches, uint8_t* numberOfSwitches) { ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t** switches, uint8_t* numberOfSwitches) {
return DeviceHandlerBase::NO_SWITCH; return DeviceHandlerBase::NO_SWITCH;
} }

View File

@ -1082,6 +1082,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/ */
void commandSwitch(ReturnValue_t onOff); void commandSwitch(ReturnValue_t onOff);
/**
* @brief This function can be used to insert device specific code during the do-send-read
* step.
*/
virtual ReturnValue_t doSendReadHook();
private: private:
/** /**
* State a cookie is in. * State a cookie is in.

View File

@ -116,8 +116,8 @@ uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t starti
// for (int i=0; i<16 ;i++) // for (int i=0; i<16 ;i++)
// { // {
// if (xor_out[i] == true) // if (xor_out[i] == true)
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before Final // crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before
//XOR //Final XOR
// } // }
// //
// crc_value = 0;// for debug mode // crc_value = 0;// for debug mode

View File

@ -14,30 +14,30 @@ class ModeMessage {
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND; static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
static const Command_t CMD_MODE_COMMAND = static const Command_t CMD_MODE_COMMAND =
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY, MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
//!REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, //! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
//!as this will break the subsystem mode machine!! //! as this will break the subsystem mode machine!!
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID( static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies 0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
//!are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any //! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
//!replies, as this will break the subsystem mode machine!! //! replies, as this will break the subsystem mode machine!!
static const Command_t REPLY_MODE_REPLY = static const Command_t REPLY_MODE_REPLY =
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
static const Command_t REPLY_MODE_INFO = static const Command_t REPLY_MODE_INFO =
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
//!inform their container of a changed mode) //! inform their container of a changed mode)
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID( static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0 0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
static const Command_t REPLY_WRONG_MODE_REPLY = static const Command_t REPLY_WRONG_MODE_REPLY =
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
//!and a transition started but was aborted; the parameters contain //! and a transition started but was aborted; the parameters contain
//!the mode that was reached //! the mode that was reached
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID( static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY 0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID( static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply. 0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
//!every child. This command does NOT have a reply. //! every child. This command does NOT have a reply.
static Mode_t getMode(const CommandMessage* message); static Mode_t getMode(const CommandMessage* message);
static Submode_t getSubmode(const CommandMessage* message); static Submode_t getSubmode(const CommandMessage* message);

View File

@ -65,8 +65,8 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details The method sets and starts * @details The method sets and starts
* the task's period, then enters a loop that is repeated indefinitely. Within the loop, * the task's period, then enters a loop that is repeated indefinitely. Within the
* all performOperation methods of the added objects are called. Afterwards the task will be * loop, all performOperation methods of the added objects are called. Afterwards the task will be
* blocked until the next period. On missing the deadline, the deadlineMissedFunction is executed. * blocked until the next period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
virtual void taskFunctionality(void); virtual void taskFunctionality(void);

View File

@ -13,8 +13,8 @@ class ExecutableObjectIF;
* @brief This class represents a specialized task for periodic activities of multiple objects. * @brief This class represents a specialized task for periodic activities of multiple objects.
* *
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute * @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
* multiple objects that implement the ExecutableObjectIF interface. The objects must * multiple objects that implement the ExecutableObjectIF interface. The objects
* be added prior to starting the task. * must be added prior to starting the task.
* @author baetz * @author baetz
* @ingroup task_handling * @ingroup task_handling
*/ */

View File

@ -25,8 +25,8 @@ class RTEMSTaskBase {
* all other attributes are set with default values. * all other attributes are set with default values.
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99. * @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
* @param stack_size The stack size reserved by the operating system for the task. * @param stack_size The stack size reserved by the operating system for the task.
* @param nam The name of the Task, as a null-terminated String. Currently max 4 chars * @param nam The name of the Task, as a null-terminated String. Currently max 4
* supported (excluding Null-terminator), rest will be truncated * chars supported (excluding Null-terminator), rest will be truncated
*/ */
RTEMSTaskBase(rtems_task_priority priority, size_t stack_size, const char *name); RTEMSTaskBase(rtems_task_priority priority, size_t stack_size, const char *name);
/** /**

View File

@ -51,9 +51,9 @@ class RMAP : public HasReturnvaluesIF {
// MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write // MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write
// command) or the expected len was bigger than maximal expected len (read command) command was // command) or the expected len was bigger than maximal expected len (read command) command was
// not sent // not sent
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t COMMAND_NULLPOINTER // replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t
// = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write command, or // COMMAND_NULLPOINTER = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write
// nullpointer in read command // command, or nullpointer in read command
static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED = static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED =
MAKE_RETURN_CODE(0xE6); // the channel has no port set MAKE_RETURN_CODE(0xE6); // the channel has no port set
static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE = static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE =
@ -73,8 +73,8 @@ class RMAP : public HasReturnvaluesIF {
static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE( static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE(
0xD3); // a read command was issued, but get_write_rply called, or other way round 0xD3); // a read command was issued, but get_write_rply called, or other way round
static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4); // timeout static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4); // timeout
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER = // replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER
// MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL return values for // = MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL return values for
// get_reply // get_reply
static const ReturnValue_t REPLY_INTERFACE_BUSY = static const ReturnValue_t REPLY_INTERFACE_BUSY =
MAKE_RETURN_CODE(0xC0); // Interface is busy (transmission buffer still being processed) MAKE_RETURN_CODE(0xC0); // Interface is busy (transmission buffer still being processed)
@ -169,8 +169,8 @@ class RMAP : public HasReturnvaluesIF {
* @param buffer the data to write * @param buffer the data to write
* @param length length of data * @param length length of data
* @return * @return
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in
* command * write command
* - return codes of RMAPChannelIF::sendCommand() * - return codes of RMAPChannelIF::sendCommand()
*/ */
static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length); static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length);
@ -205,8 +205,8 @@ class RMAP : public HasReturnvaluesIF {
* @param cookie to cookie to read from * @param cookie to cookie to read from
* @param expLength the expected maximum length of the reply * @param expLength the expected maximum length of the reply
* @return * @return
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write * - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in
* command, or nullpointer in read command * write command, or nullpointer in read command
* - return codes of RMAPChannelIF::sendCommand() * - return codes of RMAPChannelIF::sendCommand()
*/ */
static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength); static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength);

View File

@ -73,16 +73,16 @@ class RMAPChannelIF {
* @param datalen length of data * @param datalen length of data
* @return * @return
* - @c RETURN_OK * - @c RETURN_OK
* - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending command; * - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending
* command was not sent * command; command was not sent
* - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len; command * - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len;
* was not sent
* - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw to
* handle (write command) or the expected len was bigger than maximal expected len (read command)
* command was not sent * command was not sent
* - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw
* to handle (write command) or the expected len was bigger than maximal expected len (read
* command) command was not sent
* - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set * - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set
* - @c NOT_SUPPORTED if you dont feel like implementing * - @c NOT_SUPPORTED if you dont feel like
* something... * implementing something...
*/ */
virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, const uint8_t *data, virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, const uint8_t *data,
size_t datalen) = 0; size_t datalen) = 0;
@ -97,8 +97,8 @@ class RMAPChannelIF {
* - @c REPLY_NO_REPLY no reply was received * - @c REPLY_NO_REPLY no reply was received
* - @c REPLY_NOT_SENT command was not sent, implies no reply * - @c REPLY_NOT_SENT command was not sent, implies no reply
* - @c REPLY_NOT_YET_SENT command is still waiting to be sent * - @c REPLY_NOT_YET_SENT command is still waiting to be sent
* - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still being * - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still
* processed) * being processed)
* - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last * - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last
* operation, data could not be processed. (transmission error) * operation, data could not be processed. (transmission error)
* - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value) * - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value)

View File

@ -32,10 +32,10 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C
static const uint8_t RMAP_REPLY_WRITE = static const uint8_t RMAP_REPLY_WRITE =
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY)); ((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY)); static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE) | //#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
//(1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) | //| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define //(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
//RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY)) // RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) | //#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
//(1<<RMAP_COMMAND_BIT_REPLY)) //(1<<RMAP_COMMAND_BIT_REPLY))

View File

@ -45,7 +45,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
usleep(500); usleep(500);
REQUIRE(limitIdx < 5); REQUIRE(limitIdx < 500);
} }
limitIdx = 0; limitIdx = 0;
@ -71,8 +71,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
limitIdx++; limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
// This ensures that the tests do not block indefinitely
usleep(500); usleep(500);
REQUIRE(limitIdx < 20); REQUIRE(limitIdx < 500);
} }
limitIdx = 0; limitIdx = 0;
CHECK(bytesHaveBeenRead == true); CHECK(bytesHaveBeenRead == true);
@ -89,7 +90,7 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer)); std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer));
// I am just going to assume that this string is the same across ping implementations // I am just going to assume that this string is the same across ping implementations
// of different Linux systems // of different Linux systems
REQUIRE(allTheReply.find("localhost ping statistics") != std::string::npos); REQUIRE(allTheReply.find("PING localhost") != std::string::npos);
// Now check failing command // Now check failing command
result = cmdExecutor.load("false", false, false); result = cmdExecutor.load("false", false, false);
@ -101,8 +102,9 @@ TEST_CASE("Command Executor", "[cmd-exec]") {
limitIdx++; limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead); result = cmdExecutor.check(bytesHaveBeenRead);
REQUIRE(result != CommandExecutor::COMMAND_ERROR); REQUIRE(result != CommandExecutor::COMMAND_ERROR);
// This ensures that the tests do not block indefinitely
usleep(500); usleep(500);
REQUIRE(limitIdx < 20); REQUIRE(limitIdx < 500);
} }
REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED); REQUIRE(result == HasReturnvaluesIF::RETURN_FAILED);
REQUIRE(cmdExecutor.getLastError() == 1); REQUIRE(cmdExecutor.getLastError() == 1);