Compare commits
160 Commits
1b7e94d718
...
mueller/ne
Author | SHA1 | Date | |
---|---|---|---|
39310c3fad | |||
d16c5024dc | |||
bf311757a2 | |||
a4531e4ced | |||
cbe1b65a33 | |||
80f0060cd2 | |||
97c629ad84 | |||
bf12f284fa | |||
8589f4d63a | |||
ca80589233 | |||
f2ebaed092 | |||
f0b89e98df | |||
5557d95994 | |||
fc24c9b5d8 | |||
7ef69c839c | |||
9b798d798e | |||
b13453f46b | |||
d0e322d7e2 | |||
ecde164f68 | |||
50930b41ba | |||
d6ee2ed400 | |||
f2150ff9c2 | |||
1b9c98f3fe | |||
742152b28e | |||
bf4ca56658 | |||
16ffa00155 | |||
14c681c93a | |||
0958c3a00e | |||
d699d16307 | |||
3b0fed733f | |||
23d3812fe3 | |||
dec7db3ae2 | |||
65a5abab49 | |||
0129783e34 | |||
cabe0868ec | |||
f05295bada | |||
b85ca64690 | |||
3bc3da5a8d | |||
f8c07ec9cf | |||
8199b8f359 | |||
cbc8dbcdd4 | |||
d31a5306f0 | |||
a236a5ec50 | |||
03620970e2 | |||
8fe8d810e9 | |||
9483c2809d | |||
fe3d6bd432 | |||
2a842666d5 | |||
c013fcc1f5 | |||
1b8fc2af19 | |||
72d7c43445 | |||
ab9b6c8c89 | |||
69d338f9bb | |||
68223869d5 | |||
93fda71989 | |||
7b0db08962 | |||
0956fbc740 | |||
b48e0fdc0d | |||
1d084ee22f | |||
1bea2344f6 | |||
d7e16a67a7 | |||
6021d897b8 | |||
83a6f0b5f8 | |||
a9c6c088f2 | |||
b6a3c206cc | |||
5b352978c5 | |||
819a298b19 | |||
16246d6ece | |||
5c84f12440 | |||
83c2c4825c | |||
c913fe40bf | |||
70ec08bf1d | |||
ef23665d9c | |||
eefc122292 | |||
bee33526a1 | |||
f715b65d6e | |||
c11af63015 | |||
11a22577be | |||
dc1583c932 | |||
94f1f1f908 | |||
81a7de2814 | |||
d26f230bee | |||
4db124c680 | |||
955579c856 | |||
2df66c9304 | |||
54ad6b3016 | |||
73e313c35b | |||
c6585c8645 | |||
dd2f42d22b | |||
d8a4675842 | |||
1164c21ddd | |||
77b1a85b47 | |||
652c31a683 | |||
bfe120636c | |||
a8041f220f | |||
dd636b186b | |||
3349fc36f8 | |||
f3e9277e59 | |||
d592f1ecbc | |||
6ec18171a8 | |||
518dcdef4b | |||
d9730032fd | |||
b3ac72b7db | |||
cd0cb43412 | |||
32c12b3dbf | |||
3e9acf476e | |||
99101ce2bf | |||
6b991045f7 | |||
df06064df0 | |||
337cb0d6c9 | |||
c283e0c988 | |||
448d20f3bd | |||
2316728d74 | |||
6f562e5f3e | |||
176f243194 | |||
d964fa2107 | |||
7b5ae6a445 | |||
8e362a000c | |||
7877776e24 | |||
3de0ae5a48 | |||
e0c780f21c | |||
876815b1c9 | |||
b0ecf87580 | |||
68ce8b5b08 | |||
fe03da6def | |||
95ac53c417 | |||
62f638a3d2 | |||
bd64591f30 | |||
e6a877f048 | |||
ea8c557ee8 | |||
0bdd780f82 | |||
9ec397c8b7 | |||
c54d9d7ba6 | |||
30c03c110c | |||
69f1be263a | |||
c7b5309dcb | |||
775d5632de | |||
4f3361eb2b | |||
9e6c1d60e5 | |||
12d0c23c13 | |||
5c3bb13834 | |||
292fe3e5e4 | |||
33530f2819 | |||
c0000a8635 | |||
5488ee715f | |||
0fea22d031 | |||
3b8ca09299 | |||
9a2146fa2d | |||
558550ecb9 | |||
bcbbc9763a | |||
0042372cb6 | |||
8dea13742f | |||
0f027d29d2 | |||
ce7146e468 | |||
a681a4a797 | |||
83b7b8707c | |||
4002b74ea2 | |||
4f7f8310c9 | |||
6eea711d9f | |||
9d626e0a5d |
40
CHANGELOG.md
40
CHANGELOG.md
@@ -12,6 +12,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Fixes
|
||||
|
||||
- TC Scheduler Service 11: Add size and CRC check for contained TC.
|
||||
- Only delete health table entry in `HealthHelper` destructor if
|
||||
health table was set.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
|
||||
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
|
||||
Also properly reset the reply size for successfull transfers and erroneous transfers.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
|
||||
- Bugfix for Serial Buffer Stream: Setting `doActive` to false now
|
||||
actually fully disables printing.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/680
|
||||
@@ -21,19 +28,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Added
|
||||
|
||||
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
|
||||
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
|
||||
types of telemetry.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
|
||||
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
|
||||
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
|
||||
pointer.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
|
||||
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
||||
- `UioMapper` is able to resolve symlinks now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||
- Add new `UnsignedByteField` class
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
||||
|
||||
## Changes
|
||||
|
||||
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
||||
- Moved some container returnvalues to dedicated header and namespace
|
||||
to they can be used without template specification.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
|
||||
- Remove default secondary header argument for
|
||||
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
|
||||
`uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)`
|
||||
@@ -62,6 +70,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||
- Make functions `const` where it makes sense
|
||||
- Add `const char* getName const` abstract function
|
||||
@@ -222,6 +234,7 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||
Easiest solution for now: Keep this option OFF by default.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||
inside `fsfw/version.h`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||
@@ -236,17 +249,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||
- `Subsystem`: New API to add table and sequence entries
|
||||
|
||||
## HAL
|
||||
|
||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||
differing speeds and modes are attached to one bus.
|
||||
- SPI: Getter functions for SPI speed and mode.
|
||||
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
||||
|
||||
## Fixed
|
||||
|
||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||
|
@@ -122,6 +122,7 @@ if(UNIX)
|
||||
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
|
||||
OFF)
|
||||
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
|
||||
option(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS "Add serial drivers" ON)
|
||||
endif()
|
||||
|
||||
# Optional sources
|
||||
@@ -195,7 +196,7 @@ message(
|
||||
)
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||
# Not installed, so use FetchContent to download and provide etl
|
||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
message(
|
||||
@@ -326,7 +327,8 @@ if(FSFW_BUILD_TESTS)
|
||||
"/usr/local/include/*"
|
||||
"*/fsfw_tests/*"
|
||||
"*/catch2-src/*"
|
||||
"*/fsfw_hal/*")
|
||||
"*/fsfw_hal/*"
|
||||
"unittests/*")
|
||||
endif()
|
||||
|
||||
target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs
|
||||
@@ -344,8 +346,15 @@ if(FSFW_BUILD_TESTS)
|
||||
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||
else()
|
||||
setup_target_for_coverage_lcov(
|
||||
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||
NAME
|
||||
${FSFW_TEST_TGT}_coverage
|
||||
EXECUTABLE
|
||||
${FSFW_TEST_TGT}
|
||||
DEPENDENCIES
|
||||
${FSFW_TEST_TGT}
|
||||
GENHTML_ARGS
|
||||
--html-epilog
|
||||
${CMAKE_SOURCE_DIR}/unittests/lcov_epilog.html)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -5,7 +5,7 @@ RUN apt-get --yes upgrade
|
||||
|
||||
#tzdata is a dependency, won't install otherwise
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz
|
||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync
|
||||
|
||||
RUN python3 -m pip install sphinx breathe
|
||||
|
||||
@@ -23,3 +23,7 @@ RUN git clone https://github.com/ETLCPP/etl.git && \
|
||||
|
||||
#ssh needs a valid user to work
|
||||
RUN adduser --uid 114 jenkins
|
||||
|
||||
#add documentation server to known hosts
|
||||
RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
||||
RUN echo "|1|CcBvBc3EG03G+XM5rqRHs6gK/Gg=|oGeJQ+1I8NGI2THIkJsW92DpTzs= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
14
automation/Jenkinsfile
vendored
14
automation/Jenkinsfile
vendored
@@ -5,7 +5,7 @@ pipeline {
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'fsfw-ci:d5'
|
||||
image 'fsfw-ci:d6'
|
||||
args '--network host'
|
||||
}
|
||||
}
|
||||
@@ -52,14 +52,12 @@ pipeline {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/development'
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/development/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/development'
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,14 +71,12 @@ pipeline {
|
||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||
sh 'make Sphinx'
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r docs/sphinx/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/master'
|
||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
||||
}
|
||||
}
|
||||
dir(BUILDDIR) {
|
||||
sshagent(credentials: ['documentation-buildfix']) {
|
||||
sh 'ssh -o StrictHostKeyChecking=no buildfix@documentation.intra.irs.uni-stuttgart.de rm -rf /mnt/data/www/html/fsfw/coverage/master/*'
|
||||
sh 'scp -o StrictHostKeyChecking=no -r fsfw-tests_coverage/* buildfix@documentation.intra.irs.uni-stuttgart.de:/mnt/data/www/html/fsfw/coverage/master'
|
||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -140,7 +140,7 @@ find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( GCOVR_PATH gcovr )
|
||||
find_program( CPPFILT_PATH NAMES c++filt )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
|
@@ -1,40 +0,0 @@
|
||||
Configuring the FSFW
|
||||
======
|
||||
|
||||
The FSFW can be configured via the `fsfwconfig` folder. A template folder has
|
||||
been provided to have a starting point for this. The folder should be added
|
||||
to the include path. The primary configuration file is the `FSFWConfig.h` folder. Some
|
||||
of the available options will be explained in more detail here.
|
||||
|
||||
# Auto-Translation of Events
|
||||
|
||||
The FSFW allows the automatic translation of events, which allows developers to track triggered
|
||||
events directly via console output. Using this feature requires:
|
||||
|
||||
1. `FSFW_OBJ_EVENT_TRANSLATION` set to 1 in the configuration file.
|
||||
2. Special auto-generated translation files which translate event IDs and object IDs into
|
||||
human readable strings. These files can be generated using the
|
||||
[modgen Python scripts](https://git.ksat-stuttgart.de/source/modgen.git).
|
||||
3. The generated translation files for the object IDs should be named `translatesObjects.cpp`
|
||||
and `translateObjects.h` and should be copied to the `fsfwconfig/objects` folder
|
||||
4. The generated translation files for the event IDs should be named `translateEvents.cpp` and
|
||||
`translateEvents.h` and should be copied to the `fsfwconfig/events` folder
|
||||
|
||||
An example implementations of these translation file generators can be found as part
|
||||
of the [SOURCE project here](https://git.ksat-stuttgart.de/source/sourceobsw/-/tree/development/generators)
|
||||
or the [FSFW example](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/generators)
|
||||
|
||||
## Configuring the Event Manager
|
||||
|
||||
The number of allowed subscriptions can be modified with the following
|
||||
parameters:
|
||||
|
||||
``` c++
|
||||
namespace fsfwconfig {
|
||||
//! Configure the allocated pool sizes for the event manager.
|
||||
static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
|
||||
static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
|
||||
static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
|
||||
}
|
||||
```
|
||||
|
@@ -1 +0,0 @@
|
||||
## Controllers
|
@@ -1,55 +0,0 @@
|
||||
## FSFW Core Modules
|
||||
|
||||
These core modules provide the most important functionalities of the
|
||||
Flight Software Framework
|
||||
|
||||
### Clock
|
||||
|
||||
* This is a class of static functions that can be used at anytime
|
||||
* Leap Seconds must be set if any time conversions from UTC to other times is used
|
||||
|
||||
### ObjectManager
|
||||
|
||||
* Must be created during program startup
|
||||
* The component which handles all references. All SystemObjects register at this component.
|
||||
* Any SystemObject needs to have a unique ObjectId. Those can be managed like objects::framework_objects.
|
||||
* A reference to an object can be get by calling the following function. T must be the specific Interface you want to call.
|
||||
A nullptr check of the returning Pointer must be done. This function is based on Run-time type information.
|
||||
|
||||
```cpp
|
||||
template <typename T> T* ObjectManagerIF::get( object_id_t id )
|
||||
```
|
||||
* A typical way to create all objects on startup is a handing a static produce function to the
|
||||
ObjectManager on creation. By calling objectManager->initialize() the produce function will be
|
||||
called and all SystemObjects will be initialized afterwards.
|
||||
|
||||
### Event Manager
|
||||
|
||||
* Component which allows routing of events
|
||||
* Other objects can subscribe to specific events, ranges of events or all events of an object.
|
||||
* Subscriptions can be done during runtime but should be done during initialization
|
||||
* Amounts of allowed subscriptions can be configured in `FSFWConfig.h`
|
||||
|
||||
### Health Table
|
||||
|
||||
* A component which holds every health state
|
||||
* Provides a thread safe way to access all health states without the need of message exchanges
|
||||
|
||||
### Stores
|
||||
|
||||
* The message based communication can only exchange a few bytes of information inside the message
|
||||
itself. Therefore, additional information can be exchanged with Stores. With this, only the
|
||||
store address must be exchanged in the message.
|
||||
* Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC
|
||||
Store is used. For outgoing TM a TM store is used.
|
||||
* All of them should use the Thread Safe Class storagemanager/PoolManager
|
||||
|
||||
### Tasks
|
||||
|
||||
There are two different types of tasks:
|
||||
* The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
|
||||
insertion to the Tasks.
|
||||
* FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for
|
||||
DeviceHandlers, where polling should be in a defined order. An example can be found in
|
||||
`defaultcfg/fsfwconfig/pollingSequence` folder
|
||||
|
@@ -1 +0,0 @@
|
||||
## Device Handlers
|
@@ -1,135 +0,0 @@
|
||||
High-level overview
|
||||
======
|
||||
|
||||
# Structure
|
||||
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
|
||||
widely available, even with older compilers.
|
||||
The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions are provided in the
|
||||
FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
|
||||
|
||||
# Failure Handling
|
||||
|
||||
Functions should return a defined `ReturnValue_t` to signal to the caller that something has
|
||||
gone wrong. Returnvalues must be unique. For this the function `returnvalue::makeCode`
|
||||
or the macro `MAKE_RETURN` can be used. The `CLASS_ID` is a unique id for that type of object.
|
||||
See `returnvalues/FwClassIds` folder. The user can add custom `CLASS_ID`s via the
|
||||
`fsfwconfig` folder.
|
||||
|
||||
# OSAL
|
||||
|
||||
The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS.
|
||||
The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
|
||||
The [OSAL README](doc/README-osal.md#top) provides more detailed information on provided components
|
||||
and how to use them.
|
||||
|
||||
# Core Components
|
||||
|
||||
The FSFW has following core components. More detailed informations can be found in the
|
||||
[core component section](doc/README-core.md#top):
|
||||
|
||||
1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
|
||||
with fixed timeslots
|
||||
2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
|
||||
to the object handles.
|
||||
3. Static Stores: Different stores are provided to store data of variable size (like telecommands
|
||||
or small telemetry) in a pool structure without using dynamic memory allocation.
|
||||
These pools are allocated up front.
|
||||
3. Clock: This module provided common time related functions
|
||||
4. EventManager: This module allows routing of events generated by `SystemObjects`
|
||||
5. HealthTable: A component which stores the health states of objects
|
||||
|
||||
# Static IDs in the framework
|
||||
|
||||
Some parts of the framework use a static routing address for communication.
|
||||
An example setup of ids can be found in the example config in `defaultcft/fsfwconfig/objects`
|
||||
inside the function `Factory::setStaticFrameworkObjectIds()`.
|
||||
|
||||
# Events
|
||||
|
||||
Events are tied to objects. EventIds can be generated by calling the Macro MAKE_EVENT.
|
||||
This works analog to the returnvalues. Every object that needs own EventIds has to get a
|
||||
unique SUBSYSTEM_ID. Every SystemObject can call triggerEvent from the parent class.
|
||||
Therefore, event messages contain the specific EventId and the objectId of the object that
|
||||
has triggered.
|
||||
|
||||
# Internal Communication
|
||||
|
||||
Components communicate mostly via Messages through Queues.
|
||||
Those queues are created by calling the singleton `QueueFactory::instance()->create()` which
|
||||
will create `MessageQueue` instances for the used OSAL.
|
||||
|
||||
# External Communication
|
||||
|
||||
The external communication with the mission control system is mostly up to the user implementation.
|
||||
The FSFW provides PUS Services which can be used to but don't need to be used.
|
||||
The services can be seen as a conversion from a TC to a message based communication and back.
|
||||
|
||||
## TMTC Communication
|
||||
|
||||
The FSFW provides some components to facilitate TMTC handling via the PUS commands.
|
||||
For example, a UDP or TCP PUS server socket can be opened on a specific port using the
|
||||
files located in `osal/common`. The FSFW example uses this functionality to allow sending telecommands
|
||||
and receiving telemetry using the [TMTC commander application](https://github.com/spacefisch/tmtccmd).
|
||||
Simple commands like the PUS Service 17 ping service can be tested by simply running the
|
||||
`tmtc_client_cli.py` or `tmtc_client_gui.py` utility in
|
||||
the [example tmtc folder](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example_public/src/branch/master/tmtc)
|
||||
while the `fsfw_example` application is running.
|
||||
|
||||
More generally, any class responsible for handling incoming telecommands and sending telemetry
|
||||
can implement the generic `TmTcBridge` class located in `tmtcservices`. Many applications
|
||||
also use a dedicated polling task for reading telecommands which passes telecommands
|
||||
to the `TmTcBridge` implementation.
|
||||
|
||||
## CCSDS Frames, CCSDS Space Packets and PUS
|
||||
|
||||
If the communication is based on CCSDS Frames and Space Packets, several classes can be used to
|
||||
distributed the packets to the corresponding services. Those can be found in `tcdistribution`.
|
||||
If Space Packets are used, a timestamper has to be provided by the user.
|
||||
An example can be found in the `timemanager` folder, which uses `CCSDSTime::CDS_short`.
|
||||
|
||||
# Device Handlers
|
||||
|
||||
DeviceHandlers are another important component of the FSFW.
|
||||
The idea is, to have a software counterpart of every physical device to provide a simple mode,
|
||||
health and commanding interface. By separating the underlying Communication Interface with
|
||||
`DeviceCommunicationIF`, a device handler (DH) can be tested on different hardware.
|
||||
The DH has mechanisms to monitor the communication with the physical device which allow
|
||||
for FDIR reaction. Device Handlers can be created by implementing `DeviceHandlerBase`.
|
||||
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
|
||||
related [documentation section](doc/README-devicehandlers.md#top).
|
||||
|
||||
# Modes and Health
|
||||
|
||||
The two interfaces `HasModesIF` and `HasHealthIF` provide access for commanding and monitoring
|
||||
of components. On-board Mode Management is implement in hierarchy system.
|
||||
DeviceHandlers and Controllers are the lowest part of the hierarchy.
|
||||
The next layer are Assemblies. Those assemblies act as a component which handle
|
||||
redundancies of handlers. Assemblies share a common core with the next level which
|
||||
are the Subsystems.
|
||||
|
||||
Those Assemblies are intended to act as auto-generated components from a database which describes
|
||||
the subsystem modes. The definitions contain transition and target tables which contain the DH,
|
||||
Assembly and Controller Modes to be commanded.
|
||||
Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a
|
||||
switch into any higher AOCS mode might first turn on the sensors, than the actuators and the
|
||||
controller as last component.
|
||||
The target table is used to describe the state that is checked continuously by the subsystem.
|
||||
All of this allows System Modes to be generated as Subsystem object as well from the same database.
|
||||
This System contains list of subsystem modes in the transition and target tables.
|
||||
Therefore, it allows a modular system to create system modes and easy commanding of those, because
|
||||
only the highest components must be commanded.
|
||||
|
||||
The health state represents if the component is able to perform its tasks.
|
||||
This can be used to signal the system to avoid using this component instead of a redundant one.
|
||||
The on-board FDIR uses the health state for isolation and recovery.
|
||||
|
||||
# Unit Tests
|
||||
|
||||
Unit Tests are provided in the unittest folder. Those use the catch2 framework but do not include
|
||||
catch2 itself. More information on how to run these tests can be found in the separate
|
||||
[`fsfw_tests` reposoitory](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests)
|
@@ -1,174 +0,0 @@
|
||||
## Local Data Pools Developer Information
|
||||
|
||||
The following text is targeted towards mission software developers which would like
|
||||
to use the local data pools provided by the FSFW to store data like sensor values so they can be
|
||||
used by other software objects like controllers as well. If a custom class should have a local
|
||||
pool which can be used by other software objects as well, following steps have to be performed:
|
||||
|
||||
1. Create a `LocalDataPoolManager` member object in the custom class
|
||||
2. Implement the `HasLocalDataPoolIF` with specifies the interface between the local pool manager
|
||||
and the class owning the local pool.
|
||||
|
||||
The local data pool manager is also able to process housekeeping service requests in form
|
||||
of messages, generate periodic housekeeping packet, generate notification and snapshots of changed
|
||||
variables and datasets and process notifications and snapshots coming from other objects.
|
||||
The two former tasks are related to the external interface using telemetry and telecommands (TMTC)
|
||||
while the later two are related to data consumers like controllers only acting on data change
|
||||
detected by the data creator instead of checking the data manually each cycle. Two important
|
||||
framework classes `DeviceHandlerBase` and `ExtendedControllerBase` already perform the two steps
|
||||
shown above so the steps required are altered slightly.
|
||||
|
||||
### Storing and Accessing pool data
|
||||
|
||||
The pool manager is responsible for thread-safe access of the pool data, but the actual
|
||||
access to the pool data from the point of view of a mission software developer happens via proxy
|
||||
classes like pool variable classes. These classes store a copy
|
||||
of the pool variable with the matching datatype and copy the actual data from the local pool
|
||||
on a `read` call. Changed variables can then be written to the local pool with a `commit` call.
|
||||
The `read` and `commit` calls are thread-safe and can be called concurrently from data creators
|
||||
and data consumers. Generally, a user will create a dataset class which in turn groups all
|
||||
cohesive pool variables. These sets simply iterator over the list of variables and call the
|
||||
`read` and `commit` functions of each variable. The following diagram shows the
|
||||
high-level architecture of the local data pools.
|
||||
|
||||
.. image:: ../misc/logo/FSFW_Logo_V3_bw.png
|
||||
:alt: FSFW Logo
|
||||
|
||||
|
||||
An example is shown for using the local data pools with a Gyroscope.
|
||||
For example, the following code shows an implementation to access data from a Gyroscope taken
|
||||
from the SOURCE CubeSat project:
|
||||
|
||||
```cpp
|
||||
class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> {
|
||||
public:
|
||||
/**
|
||||
* Constructor for data users
|
||||
* @param gyroId
|
||||
*/
|
||||
GyroPrimaryDataset(object_id_t gyroId):
|
||||
StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) {
|
||||
setAllVariablesReadOnly();
|
||||
}
|
||||
|
||||
lp_var_t<float> angVelocityX = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_X, this);
|
||||
lp_var_t<float> angVelocityY = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_Y, this);
|
||||
lp_var_t<float> angVelocityZ = lp_var_t<float>(sid.objectId,
|
||||
gyrodefs::ANGULAR_VELOCITY_Z, this);
|
||||
private:
|
||||
|
||||
friend class GyroHandler;
|
||||
/**
|
||||
* Constructor for data creator
|
||||
* @param hkOwner
|
||||
*/
|
||||
GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner):
|
||||
StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {}
|
||||
};
|
||||
```
|
||||
|
||||
There is a public constructor for users which sets all variables to read-only and there is a
|
||||
constructor for the GyroHandler data creator by marking it private and declaring the `GyroHandler`
|
||||
as a friend class. Both the atittude controller and the `GyroHandler` can now
|
||||
use the same class definition to access the pool variables with `read` and `commit` semantics
|
||||
in a thread-safe way. Generally, each class requiring access will have the set class as a member
|
||||
class. The data creator will also be generally a `DeviceHandlerBase` subclass and some additional
|
||||
steps are necessary to expose the set for housekeeping purposes.
|
||||
|
||||
### Using the local data pools in a `DeviceHandlerBase` subclass
|
||||
|
||||
It is very common to store data generated by devices like a sensor into a pool which can
|
||||
then be used by other objects. Therefore, the `DeviceHandlerBase` already has a
|
||||
local pool. Using the aforementioned example, our `GyroHandler` will now have the set class
|
||||
as a member:
|
||||
|
||||
```cpp
|
||||
class GyroHandler: ... {
|
||||
|
||||
public:
|
||||
...
|
||||
private:
|
||||
...
|
||||
GyroPrimaryDataset gyroData;
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
The constructor used for the creators expects the owner class as a parameter, so we initialize
|
||||
the object in the `GyroHandler` constructor like this:
|
||||
|
||||
```cpp
|
||||
GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF,
|
||||
CookieIF *comCookie, uint8_t switchId):
|
||||
DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId),
|
||||
gyroData(this) {}
|
||||
```
|
||||
|
||||
We need to assign the set to a reply ID used in the `DeviceHandlerBase`.
|
||||
The combination of the `GyroHandler` object ID and the reply ID will be the 64-bit structure ID
|
||||
`sid_t` and is used to globally identify the set, for example when requesting housekeeping data or
|
||||
generating update messages. We need to assign our custom set class in some way so that the local
|
||||
pool manager can access the custom data sets as well.
|
||||
By default, the `getDataSetHandle` will take care of this tasks. The default implementation for a
|
||||
`DeviceHandlerBase` subclass will use the internal command map to retrieve
|
||||
a handle to a dataset from a given reply ID. Therefore,
|
||||
we assign the set in the `fillCommandAndReplyMap` function:
|
||||
|
||||
```cpp
|
||||
void GyroHandler::fillCommandAndReplyMap() {
|
||||
...
|
||||
this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Now, we need to create the actual pool entries as well, using the `initializeLocalDataPool`
|
||||
function. Here, we also immediately subscribe for periodic housekeeping packets
|
||||
with an interval of 4 seconds. They are still disabled in this example and can be enabled
|
||||
with a housekeeping service command.
|
||||
|
||||
```cpp
|
||||
ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
|
||||
LocalDataPoolManager &poolManager) {
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z,
|
||||
new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42,
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43,
|
||||
new PoolEntry<uint8_t>({0}));
|
||||
|
||||
poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
```
|
||||
|
||||
Now, if we receive some sensor data and converted them into the right format,
|
||||
we can write it into the pool like this, using a guard class to ensure the set is commited back
|
||||
in any case:
|
||||
|
||||
```cpp
|
||||
PoolReadGuard readHelper(&gyroData);
|
||||
if(readHelper.getReadResult() == returnvalue::OK) {
|
||||
if(not gyroData.isValid()) {
|
||||
gyroData.setValidity(true, true);
|
||||
}
|
||||
|
||||
gyroData.angVelocityX = angularVelocityX;
|
||||
gyroData.angVelocityY = angularVelocityY;
|
||||
gyroData.angVelocityZ = angularVelocityZ;
|
||||
}
|
||||
```
|
||||
|
||||
The guard class will commit the changed data on destruction automatically.
|
||||
|
||||
### Using the local data pools in a `ExtendedControllerBase` subclass
|
||||
|
||||
Coming soon
|
||||
|
||||
|
@@ -1,32 +0,0 @@
|
||||
# Operating System Abstraction Layer (OSAL)
|
||||
|
||||
Some specific information on the provided OSALs are provided.
|
||||
|
||||
## Linux OSAL
|
||||
|
||||
This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for
|
||||
embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support
|
||||
and real-time functionalities. For most UNIX systems, this is done by adding `-lrt` and `-lpthread` to the linked libraries in the compilation process. The CMake build support provided will do this automatically for the `fsfw` target. It should be noted that most UNIX systems need to be configured specifically to allow the real-time functionalities required by the FSFW.
|
||||
|
||||
More information on how to set up a Linux system accordingly can be found in the
|
||||
[Linux README of the FSFW example application](https://egit.irs.uni-stuttgart.de/fsfw/fsfw_example/src/branch/master/doc/README-linux.md#top)
|
||||
|
||||
## Hosted OSAL
|
||||
|
||||
This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation). Cross-platform serial port (USB) support might be added soon.
|
||||
|
||||
## FreeRTOS OSAL
|
||||
|
||||
FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and adding the `FreeRTOSConfig.h` file location to the include path. This OSAL has only been tested extensively with the pre-emptive scheduler configuration so far but it should in principle also be possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme. When using newlib (nano), it is also recommended to add `#define configUSE_NEWLIB_REENTRANT` to the FreeRTOS configuration file to ensure thread-safety.
|
||||
|
||||
When using this OSAL, developers also need to provide an implementation for the `vRequestContextSwitchFromISR` function. This has been done because the call to request a context switch from an ISR is generally located in the `portmacro.h` header and is different depending on the target architecture or device.
|
||||
|
||||
## RTEMS OSAL
|
||||
|
||||
The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop.
|
||||
|
||||
## TCP/IP socket abstraction
|
||||
|
||||
The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets have been imlemented. This is very useful to test TMTC handling either on the host computer directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending TMTC packets via Ethernet.
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
## PUS Services
|
@@ -50,6 +50,11 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
#
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_theme_options = {
|
||||
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||
}
|
||||
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
|
@@ -6,15 +6,14 @@ High-level overview
|
||||
Structure
|
||||
----------
|
||||
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++17 as baseline.
|
||||
It also uses dynamic allocation during the initialization but provides
|
||||
static containers during runtime.
|
||||
This simplifies the instantiation of objects and allows the usage of some
|
||||
standard containers.
|
||||
Dynamic Allocation after initialization is discouraged and different solutions
|
||||
are provided in the FSFW to achieve that. The fsfw uses run-time type
|
||||
information but will not throw exceptions.
|
||||
The general structure is driven by the usage of interfaces provided by objects.
|
||||
The FSFW uses C++17 as baseline. Most modern compilers like GCC should have support for this
|
||||
standard, even for micocontrollers.
|
||||
|
||||
The FSFW might use dynamic allocation during program initialization but not during runtime.
|
||||
It offers pool objects, static containers and it also exposes the
|
||||
`Embedded Template Library <https://www.etlcpp.com/>`_ to allow writing code which does not perform
|
||||
allocation during runtime. The fsfw uses run-time type information but will not throw exceptions.
|
||||
|
||||
Failure Handling
|
||||
-----------------
|
||||
|
@@ -207,7 +207,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list:
|
||||
def perform_lcov_operation(directory: str, chdir: bool):
|
||||
if chdir:
|
||||
os.chdir(directory)
|
||||
cmd_runner("cmake --build . -- fsfw-tests_coverage -j")
|
||||
cmd_runner("cmake --build . -j -- fsfw-tests_coverage")
|
||||
|
||||
|
||||
def determine_build_dir(build_dir_list: List[str]):
|
||||
|
@@ -16,8 +16,8 @@ class CommandActionHelper {
|
||||
public:
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief A List that stores its values in an array.
|
||||
@@ -19,9 +20,6 @@ class ArrayList {
|
||||
friend class SerialArrayListAdapter;
|
||||
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
|
||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
|
||||
|
||||
/**
|
||||
* This is the allocating constructor.
|
||||
* It allocates an array of the specified size.
|
||||
@@ -187,7 +185,7 @@ class ArrayList {
|
||||
*/
|
||||
ReturnValue_t insert(T entry) {
|
||||
if (size >= maxSize_) {
|
||||
return FULL;
|
||||
return containers::LIST_FULL;
|
||||
}
|
||||
entries[size] = entry;
|
||||
++size;
|
||||
|
@@ -20,15 +20,19 @@ class FixedArrayList : public ArrayList<T, count_t> {
|
||||
FixedArrayList() : ArrayList<T, count_t>(data, MAX_SIZE) {}
|
||||
|
||||
FixedArrayList(const FixedArrayList& other) : ArrayList<T, count_t>(data, MAX_SIZE) {
|
||||
memcpy(this->data, other.data, sizeof(this->data));
|
||||
this->entries = data;
|
||||
this->size = other.size;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
}
|
||||
|
||||
FixedArrayList& operator=(FixedArrayList other) {
|
||||
memcpy(this->data, other.data, sizeof(this->data));
|
||||
this->entries = data;
|
||||
this->size = other.size;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -4,8 +4,8 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "ArrayList.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief Map implementation for maps with a pre-defined size.
|
||||
@@ -24,11 +24,6 @@ class FixedMap : public SerializeIF {
|
||||
"derived class from SerializeIF to be serialize-able");
|
||||
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
|
||||
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
|
||||
|
||||
private:
|
||||
static const key_t EMPTY_SLOT = -1;
|
||||
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
|
||||
@@ -76,10 +71,10 @@ class FixedMap : public SerializeIF {
|
||||
|
||||
ReturnValue_t insert(key_t key, T value, Iterator* storedValue = nullptr) {
|
||||
if (exists(key) == returnvalue::OK) {
|
||||
return KEY_ALREADY_EXISTS;
|
||||
return containers::KEY_ALREADY_EXISTS;
|
||||
}
|
||||
if (_size == theMap.maxSize()) {
|
||||
return MAP_FULL;
|
||||
return containers::MAP_FULL;
|
||||
}
|
||||
theMap[_size].first = key;
|
||||
theMap[_size].second = value;
|
||||
@@ -93,7 +88,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t insert(std::pair<key_t, T> pair) { return insert(pair.first, pair.second); }
|
||||
|
||||
ReturnValue_t exists(key_t key) const {
|
||||
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
||||
ReturnValue_t result = containers::KEY_DOES_NOT_EXIST;
|
||||
if (findIndex(key) < _size) {
|
||||
result = returnvalue::OK;
|
||||
}
|
||||
@@ -103,7 +98,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(Iterator* iter) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex((*iter).value->first)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
@@ -114,7 +109,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(key_t key) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex(key)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
|
14
src/fsfw/container/definitions.h
Normal file
14
src/fsfw/container/definitions.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_CONTAINER_DEFINITIONS_H_
|
||||
#define FSFW_CONTAINER_DEFINITIONS_H_
|
||||
|
||||
#include "fsfw/retval.h"
|
||||
|
||||
namespace containers {
|
||||
static const ReturnValue_t KEY_ALREADY_EXISTS = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x01);
|
||||
static const ReturnValue_t MAP_FULL = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x02);
|
||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x03);
|
||||
|
||||
static const ReturnValue_t LIST_FULL = returnvalue::makeCode(CLASS_ID::ARRAY_LIST, 0x01);
|
||||
} // namespace containers
|
||||
|
||||
#endif /* FSFW_CONTAINER_DEFINITIONS_H_ */
|
@@ -13,9 +13,7 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||
}
|
||||
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@@ -570,10 +570,6 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
||||
|
||||
CommandMessage reply;
|
||||
if (result != returnvalue::OK) {
|
||||
if (result == WRONG_HK_PACKET_TYPE) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
||||
WRONG_HK_PACKET_TYPE);
|
||||
}
|
||||
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
||||
} else {
|
||||
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
||||
@@ -829,8 +825,6 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
||||
errorPrint = "Dataset not found";
|
||||
} else if (error == POOLOBJECT_NOT_FOUND) {
|
||||
errorPrint = "Pool Object not found";
|
||||
} else if (error == WRONG_HK_PACKET_TYPE) {
|
||||
errorPrint = "Wrong Packet Type";
|
||||
} else if (error == returnvalue::FAILED) {
|
||||
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
||||
errorPrint = "Generic Warning";
|
||||
|
@@ -162,7 +162,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
object_id_t getCreatorObjectId();
|
||||
|
||||
bool getReportingEnabled() const;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Returns the current periodic HK generation interval this set
|
||||
@@ -190,6 +189,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
* Used for periodic generation.
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor = 5);
|
||||
|
@@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
triggerModeHelperEvents(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
@@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
// The user needs to take care of commanding the children off in commandChildren
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
@@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||
// to wait for an off time period.
|
||||
// TODO: make time period configurable
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
@@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
@@ -12,8 +12,7 @@
|
||||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
* This class reduces the complexity of controller components which would
|
||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||
* manage the mode keeping and recovery of non-redundant devices
|
||||
* otherwise be needed for the handling of redundant devices.
|
||||
*
|
||||
* The template class monitors mode and health state of its children
|
||||
* and checks availability of devices on every detected change.
|
||||
@@ -27,9 +26,11 @@
|
||||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call #registerChild for all commanded children during initialization.
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase : public SubsystemBase {
|
||||
public:
|
||||
@@ -46,10 +47,9 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
@@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
/**
|
||||
* @brief Default periodic handler
|
||||
* @details
|
||||
* This is the default periodic handler which will be called by the SubsystemBase
|
||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||
* of children objects
|
||||
*/
|
||||
virtual void performChildOperation() override;
|
||||
virtual void performChildOperation();
|
||||
|
||||
/**
|
||||
* This function handles changed mode or health states of children
|
||||
* @return
|
||||
*/
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
@@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
/**
|
||||
* Core transition handler. The default implementation will only do something if
|
||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||
* from the #doPerformTransition call were executed successfully.
|
||||
*
|
||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||
* determine whether the target mode was reached.
|
||||
*
|
||||
* There is some special handling for certain (internal) modes:
|
||||
* - A second step is necessary. #commandChildren will be performed again
|
||||
* - The device health was overwritten. #commandChildren will be called
|
||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||
*/
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||
|
||||
/**
|
||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||
* change
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||
* variables and then calling the #commandChildren function.
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
@@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
virtual bool checkAndHandleRecovery();
|
||||
bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
@@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
|
||||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||
|
@@ -40,9 +40,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
childTransitionDelay(5000),
|
||||
transitionSourceMode(_MODE_POWER_DOWN),
|
||||
transitionSourceSubMode(SUBMODE_NONE) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
insertInCommandMap(RAW_COMMAND_ID);
|
||||
cookieInfo.state = COOKIE_UNUSED;
|
||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||
@@ -50,6 +49,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
||||
"Invalid cookie");
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
@@ -127,18 +129,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance =
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
if (this->parent != objects::NO_OBJECT) {
|
||||
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
|
||||
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
|
||||
if (modeIF != nullptr and healthIF != nullptr) {
|
||||
setParentQueue(modeIF->getCommandQueue());
|
||||
}
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
@@ -369,17 +359,20 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) {
|
||||
// NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
|
||||
childTransitionFailure = CHILD_TIMEOUT;
|
||||
transitionSourceMode = _MODE_SHUT_DOWN;
|
||||
transitionSourceSubMode = SUBMODE_NONE;
|
||||
setMode(_MODE_START_UP);
|
||||
callChildStatemachine();
|
||||
}
|
||||
} break;
|
||||
case _MODE_WAIT_OFF: {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (powerSwitcher == nullptr) {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
@@ -580,9 +573,6 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
mode = newMode;
|
||||
modeChanged();
|
||||
setNormalDatapoolEntriesInvalid();
|
||||
if (newMode == MODE_OFF) {
|
||||
disableCommandsAndReplies();
|
||||
}
|
||||
if (!isTransitionalMode()) {
|
||||
modeHelper.modeChanged(newMode, newSubmode);
|
||||
announceMode(false);
|
||||
@@ -1288,7 +1278,6 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
||||
if (iter->second.command != deviceCommandMap.end()) {
|
||||
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
||||
|
||||
// This may fail, but we'll ignore the fault.
|
||||
if (queueId != NO_COMMANDER) {
|
||||
// This may fail, but we'll ignore the fault.
|
||||
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
||||
@@ -1467,8 +1456,6 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||
uint32_t parameter) {}
|
||||
|
||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||
|
||||
void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
@@ -1491,7 +1478,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
startTransition(MODE_ON, SUBMODE_NONE);
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@@ -1575,40 +1562,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
||||
}
|
||||
return commandIter->second.sendReplyTo;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
for (auto& command : deviceCommandMap) {
|
||||
if (command.second.isExecuting) {
|
||||
command.second.isExecuting = false;
|
||||
}
|
||||
}
|
||||
for (auto& reply : deviceReplyMap) {
|
||||
if (!reply.second.periodic) {
|
||||
if (reply.second.countdown != nullptr) {
|
||||
reply.second.countdown->timeOut();
|
||||
} else {
|
||||
reply.second.delayCycles = 0;
|
||||
}
|
||||
reply.second.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
||||
ReturnValue_t result) {
|
||||
auto commandIter = deviceCommandMap.find(action);
|
||||
if (commandIter == deviceCommandMap.end()) {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
commandIter->second.isExecuting = false;
|
||||
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
#include "fsfw/util/dataWrapper.h"
|
||||
|
||||
namespace Factory {
|
||||
void setStaticFrameworkObjectIds();
|
||||
@@ -103,9 +102,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setParent(object_id_t parent);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
/**
|
||||
@@ -399,8 +395,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
||||
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
||||
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
|
||||
|
||||
/**
|
||||
* Helper function to get pending command. This is useful for devices
|
||||
* like SPI sensors to identify the last sent command.
|
||||
@@ -469,14 +463,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @brief This is a helper method to insert replies in the reply map.
|
||||
* @param deviceCommand Identifier of the reply to add.
|
||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||
* until it times out.
|
||||
* until it times out.
|
||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c returnvalue::OK when the command was successfully inserted,
|
||||
* - @c returnvalue::FAILED else.
|
||||
*/
|
||||
@@ -661,12 +655,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||
uint32_t parameter = 0);
|
||||
|
||||
/**
|
||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||
* to startup immediately.
|
||||
*/
|
||||
virtual Submode_t getInitialSubmode();
|
||||
|
||||
protected:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||
|
||||
@@ -785,18 +773,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* This is used to keep track of pending replies.
|
||||
*/
|
||||
struct DeviceReplyInfo {
|
||||
//! For Command-Reply combinations:
|
||||
//! The maximum number of cycles the handler should wait for a reply
|
||||
//! to this command.
|
||||
//!
|
||||
//! Reply Only:
|
||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
||||
//! definition for delay
|
||||
uint16_t maxDelayCycles;
|
||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
||||
//! For non-periodic replies without a command, this variable is unused.
|
||||
//! A runtime value of 0 means there is no reply is currently expected.
|
||||
//! The currently remaining cycles the handler should wait for a reply,
|
||||
//! 0 means there is no reply expected
|
||||
uint16_t delayCycles;
|
||||
size_t replyLen = 0; //!< Expected size of the reply.
|
||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||
@@ -852,7 +833,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
/** Pointer to the used FDIR instance. If not provided by child,
|
||||
* default class is instantiated. */
|
||||
FailureIsolationBase *fdirInstance;
|
||||
object_id_t parent = objects::NO_OBJECT;
|
||||
|
||||
//! To correctly delete the default instance.
|
||||
bool defaultFDIRUsed;
|
||||
@@ -1140,22 +1120,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t doSendReadHook();
|
||||
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
virtual void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
virtual void doGetRead();
|
||||
|
||||
private:
|
||||
/**
|
||||
* State a cookie is in.
|
||||
@@ -1291,6 +1255,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - if the action was successful, the reply timout counter is initialized
|
||||
*/
|
||||
void doGetWrite(void);
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a timeout to detect missed replies.
|
||||
@@ -1344,11 +1323,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||
const char *errorPrint = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Disables all commands and replies when device is set to MODE_OFF
|
||||
*/
|
||||
void disableCommandsAndReplies();
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||
|
@@ -29,7 +29,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
// Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
|
@@ -109,7 +109,6 @@ class DeviceHandlerIF {
|
||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||
|
||||
|
@@ -1,10 +1,9 @@
|
||||
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
|
||||
#include "fsfw/action/HasActionsIF.h"
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
#include "fsfw/util/dataWrapper.h"
|
||||
#include "../action/HasActionsIF.h"
|
||||
#include "../objectmanager/SystemObjectIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
|
||||
class DeviceTmReportingWrapper : public SerializeIF {
|
||||
public:
|
||||
|
@@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
||||
parentQueue(parentQueue),
|
||||
commandQueue(),
|
||||
healthHelper(this, setObjectId) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
||||
}
|
||||
|
||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@@ -18,9 +18,8 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
||||
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(
|
||||
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
||||
EventMessage::EVENT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
EventManager::~EventManager() {
|
||||
@@ -47,20 +46,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();
|
||||
@@ -206,19 +194,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 */
|
||||
|
@@ -43,7 +43,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;
|
||||
|
@@ -9,9 +9,8 @@
|
||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue =
|
||||
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
FailureIsolationBase::~FailureIsolationBase() {
|
||||
@@ -62,12 +61,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||
if (parentIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object "
|
||||
<< "invalid" << std::endl;
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
||||
#else
|
||||
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
||||
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object"
|
||||
<< "invalid." << std::endl;
|
||||
#endif
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
|
@@ -12,12 +12,13 @@
|
||||
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
|
||||
public:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
||||
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
||||
//! FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
||||
//! FDIR turns off device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
||||
static const Event FDIR_CHANGED_STATE =
|
||||
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
||||
//!< (oldState) to par1 (newState).
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
||||
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
||||
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
||||
|
||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||
|
@@ -40,7 +40,6 @@ class HasFileSystemIF {
|
||||
//! [EXPORT] : P1: Can be file system specific error code
|
||||
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
|
||||
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
|
||||
static constexpr ReturnValue_t FILESYSTEM_INACTIVE = MAKE_RETURN_CODE(2);
|
||||
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
|
||||
|
||||
//! [EXPORT] : File system is currently busy
|
||||
|
@@ -11,8 +11,7 @@ DleParser::DleParser(SimpleRingBuffer& decodeRingBuf, DleEncoder& decoder, BufPa
|
||||
: decodeRingBuf(decodeRingBuf),
|
||||
decoder(decoder),
|
||||
encodedBuf(encodedBuf),
|
||||
decodedBuf(decodedBuf) {
|
||||
}
|
||||
decodedBuf(decodedBuf) {}
|
||||
|
||||
ReturnValue_t DleParser::passData(const uint8_t* data, size_t len) {
|
||||
if (data == nullptr or len == 0) {
|
||||
@@ -24,7 +23,7 @@ ReturnValue_t DleParser::passData(const uint8_t* data, size_t len) {
|
||||
ReturnValue_t DleParser::parseRingBuf(size_t& readSize) {
|
||||
ctx.setType(DleParser::ContextType::NONE);
|
||||
size_t availableData = decodeRingBuf.getAvailableReadData();
|
||||
if(availableData == 0) {
|
||||
if (availableData == 0) {
|
||||
return NO_PACKET_FOUND;
|
||||
}
|
||||
if (availableData > encodedBuf.second) {
|
||||
@@ -106,7 +105,7 @@ void DleParser::defaultFoundPacketHandler(uint8_t* packet, size_t len, void* arg
|
||||
}
|
||||
|
||||
void DleParser::defaultErrorHandler() {
|
||||
if(ctx.getType() != DleParser::ContextType::ERROR) {
|
||||
if (ctx.getType() != DleParser::ContextType::ERROR) {
|
||||
errorPrinter("No error");
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +125,8 @@ void DleParser::defaultErrorHandler() {
|
||||
case (ErrorTypes::ENCODED_BUF_TOO_SMALL):
|
||||
case (ErrorTypes::DECODING_BUF_TOO_SMALL): {
|
||||
char opt[64];
|
||||
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu", ctx.decodedPacket.second);
|
||||
snprintf(opt, sizeof(opt), ": Too small for packet with length %zu",
|
||||
ctx.decodedPacket.second);
|
||||
if (ctx.error.first == ErrorTypes::ENCODED_BUF_TOO_SMALL) {
|
||||
errorPrinter("Encoded buf too small", opt);
|
||||
} else {
|
||||
@@ -168,10 +168,6 @@ ReturnValue_t DleParser::confirmBytesRead(size_t bytesRead) {
|
||||
return decodeRingBuf.deleteData(bytesRead);
|
||||
}
|
||||
|
||||
const DleParser::Context& DleParser::getContext() {
|
||||
return ctx;
|
||||
}
|
||||
const DleParser::Context& DleParser::getContext() { return ctx; }
|
||||
|
||||
void DleParser::reset() {
|
||||
decodeRingBuf.clear();
|
||||
}
|
||||
void DleParser::reset() { decodeRingBuf.clear(); }
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#include "fsfw/globalfunctions/timevalOperations.h"
|
||||
|
||||
timeval& operator+=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
int64_t sum = static_cast<int64_t>(lhs.tv_sec) * 1000000. + lhs.tv_usec;
|
||||
sum += static_cast<int64_t>(rhs.tv_sec) * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
|
@@ -16,24 +16,26 @@ class HasHealthIF {
|
||||
};
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
|
||||
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3);
|
||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
||||
//! P1: New Health, P2: Old Health
|
||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||
//! Assembly overwrites health information of children to keep satellite alive.
|
||||
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
||||
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
||||
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
||||
//! Recovery is ongoing. Comes twice during recovery.
|
||||
//! P1: 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
||||
//! Recovery was completed. Not necessarily successful. No parameters.
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
||||
static const Event OVERWRITING_HEALTH =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
||||
//!< satellite alive.
|
||||
static const Event TRYING_RECOVERY =
|
||||
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
||||
//!< power-cycle). No parameters.
|
||||
static const Event RECOVERY_STEP =
|
||||
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
||||
//!< 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(
|
||||
12,
|
||||
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
|
||||
|
||||
virtual ~HasHealthIF() {}
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@@ -5,7 +5,11 @@
|
||||
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
|
||||
: objectId(objectId), owner(owner) {}
|
||||
|
||||
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
|
||||
HealthHelper::~HealthHelper() {
|
||||
if (healthTable != nullptr) {
|
||||
healthTable->removeObject(objectId);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
|
@@ -7,13 +7,11 @@
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
@@ -38,14 +36,15 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
||||
<< newStoreHits << std::endl;
|
||||
<< "occured!" << std::endl;
|
||||
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||
#else
|
||||
sif::printDebug(
|
||||
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
||||
"| %lu\n",
|
||||
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
||||
static_cast<unsigned int>(newStoreHits));
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ class CommandMessageIF {
|
||||
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
||||
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
||||
//! Reply indicating that the current command was rejected,
|
||||
//! Parameter 1 should contain the error code
|
||||
//! par1 should contain the error code
|
||||
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
||||
|
||||
virtual ~CommandMessageIF(){};
|
||||
|
@@ -19,33 +19,32 @@ class HasModesIF {
|
||||
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
|
||||
//! An object announces changing the mode. p1: target mode. p2: target submode
|
||||
static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
|
||||
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
|
||||
static const Event CHANGING_MODE =
|
||||
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
|
||||
//!< p2: target submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(
|
||||
1,
|
||||
severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
|
||||
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
|
||||
//! Indicates a bug or configuration failure: Object is in a mode it should never be in.
|
||||
static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
|
||||
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
|
||||
//! p1: target mode. p2: target submode
|
||||
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
|
||||
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
|
||||
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
|
||||
static const Event OBJECT_IN_INVALID_MODE =
|
||||
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
|
||||
//!< mode it should never be in.
|
||||
static const Event FORCING_MODE = MAKE_EVENT(
|
||||
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
|
||||
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
|
||||
static const Event MODE_CMD_REJECTED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
|
||||
//!< called object id, Par2: return code.
|
||||
|
||||
//! 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
|
||||
static constexpr Mode_t MODE_ON = 1;
|
||||
//! The device is powered off. The only command accepted in this mode is a mode change to on.
|
||||
static constexpr Mode_t MODE_OFF = 0;
|
||||
|
||||
static constexpr Mode_t MODE_INVALID = -1;
|
||||
static constexpr Mode_t MODE_UNDEFINED = -2;
|
||||
|
||||
//! To avoid checks against magic number "0".
|
||||
static const Submode_t SUBMODE_NONE = 0;
|
||||
static const Mode_t MODE_ON =
|
||||
1; //!< 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
|
||||
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
|
||||
//!< this mode is a mode change to on.
|
||||
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
|
||||
|
||||
virtual ~HasModesIF() {}
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@@ -95,16 +95,13 @@ void ObjectManager::initialize() {
|
||||
for (auto const& it : objectList) {
|
||||
result = it.second->initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
object_id_t var = it.first;
|
||||
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
|
||||
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
|
||||
<< std::dec << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
|
||||
it.first);
|
||||
#endif
|
||||
<< std::setfill('0') << var
|
||||
<< " failed to "
|
||||
"initialize with code 0x"
|
||||
<< result << std::dec << std::setfill(' ') << std::endl;
|
||||
#endif
|
||||
errorCount++;
|
||||
}
|
||||
|
@@ -16,9 +16,7 @@ elseif(FSFW_OSAL MATCHES "host")
|
||||
|
||||
else()
|
||||
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
||||
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if(WIN32)
|
||||
add_subdirectory(host)
|
||||
|
@@ -66,8 +66,7 @@ class HasParametersIF {
|
||||
* @param newValues
|
||||
* @param startAtIndex Linear index, runs left to right, top to bottom for
|
||||
* matrix indexes.
|
||||
* @return returnvalue::OK if parameter is valid and a set function of the parameter wrapper was
|
||||
* called.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
|
@@ -211,13 +211,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (data == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
|
||||
"data pointer not set"
|
||||
<< std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"ParameterWrapper::copyFrom: Called on read-only variable "
|
||||
"or data pointer not set\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return READONLY;
|
||||
@@ -226,9 +222,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (from->readonlyData == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return SOURCE_NOT_SET;
|
||||
@@ -237,9 +233,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (type != from->type) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return DATATYPE_MISSMATCH;
|
||||
@@ -249,9 +245,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (rows == 0 or columns == 0) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return COLUMN_OR_ROWS_ZERO;
|
||||
|
@@ -29,9 +29,9 @@ class PowerSwitchIF {
|
||||
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
|
||||
//!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(
|
||||
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
/**
|
||||
* send a direct command to the Power Unit to enable/disable the specified switch.
|
||||
*
|
||||
|
@@ -41,6 +41,8 @@ class Service11TelecommandScheduling final : public PusServiceBase {
|
||||
static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2);
|
||||
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3);
|
||||
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
|
||||
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;
|
||||
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
|
||||
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
||||
|
||||
@@ -77,7 +79,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::performService
|
||||
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
|
||||
// does not work in this case as we are deleting the current element here.
|
||||
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
|
||||
if (it->first <= static_cast<uint32_t>(tNow.tv_sec)) {
|
||||
if (it->first <= tNow.tv_sec) {
|
||||
if (schedulingEnabled) {
|
||||
// release tc
|
||||
TmTcMessage releaseMsg(it->second.storeAddr);
|
||||
@@ -171,6 +173,14 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (size < PusTcIF::MIN_SIZE) {
|
||||
return CONTAINED_TC_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (CRC::crc16ccitt(data, size) != 0) {
|
||||
return CONTAINED_TC_CRC_MISSMATCH;
|
||||
}
|
||||
|
||||
// store currentPacket and receive the store address
|
||||
store_address_t addr{};
|
||||
if (tcStore->addData(&addr, data, size) != returnvalue::OK ||
|
||||
|
@@ -208,17 +208,17 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
|
||||
ReturnValue_t error = returnvalue::FAILED;
|
||||
HousekeepingMessage::getHkRequestFailureReply(reply, &error);
|
||||
failureParameter2 = error;
|
||||
return returnvalue::FAILED;
|
||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||
}
|
||||
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
|
||||
<< "reply command " << command << std::endl;
|
||||
<< "reply command " << command << "!" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"Service3Housekeeping::handleReply: Invalid reply with "
|
||||
"reply command %hu\n",
|
||||
"reply command %hu!\n",
|
||||
command);
|
||||
#endif
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
@@ -248,28 +248,19 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
|
||||
case (HousekeepingMessage::HK_REQUEST_FAILURE): {
|
||||
break;
|
||||
}
|
||||
case (CommandMessage::REPLY_REJECTED): {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
|
||||
"rejected with error code"
|
||||
<< reply->getParameter() << std::endl;
|
||||
#else
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply "
|
||||
"command "
|
||||
<< command << "" << std::endl;
|
||||
<< command << "!" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"Service3Housekeeping::handleUnrequestedReply: Invalid reply with "
|
||||
"reply command %hu\n",
|
||||
"reply command %hu!\n",
|
||||
command);
|
||||
#endif
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +275,6 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
|
||||
"Could not generate reply!\n");
|
||||
#endif
|
||||
}
|
||||
CommandingServiceBase::handleUnrequestedReply(reply);
|
||||
}
|
||||
|
||||
MessageQueueId_t Service3Housekeeping::getHkQueue() const { return commandQueue->getId(); }
|
||||
|
@@ -13,10 +13,8 @@ Service5EventReporting::Service5EventReporting(PsbParams params, size_t maxNumbe
|
||||
storeHelper(params.apid),
|
||||
tmHelper(params.serviceId, storeHelper, sendHelper),
|
||||
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
|
||||
auto mqArgs = MqArgs(getObjectId(), static_cast<void*>(this));
|
||||
psbParams.name = "PUS 5 Event Reporting";
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
}
|
||||
|
||||
Service5EventReporting::~Service5EventReporting() {
|
||||
@@ -40,6 +38,9 @@ ReturnValue_t Service5EventReporting::performService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
|
||||
#endif
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
|
@@ -6,10 +6,10 @@
|
||||
class Service9TimeManagement : public PusServiceBase {
|
||||
public:
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
||||
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||
//!< Clock could not be set. P1: Returncode.
|
||||
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
|
||||
static constexpr Event CLOCK_SET =
|
||||
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET_FAILURE =
|
||||
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
|
||||
|
||||
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
||||
|
||||
|
@@ -31,9 +31,8 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
|
||||
|
||||
LocalPool::~LocalPool() = default;
|
||||
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId);
|
||||
if (status == returnvalue::OK) {
|
||||
write(*storageId, data, size);
|
||||
}
|
||||
@@ -49,8 +48,8 @@ ReturnValue_t LocalPool::getData(store_address_t packetId, const uint8_t** packe
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getFreeElement(store_address_t* storageId, const size_t size,
|
||||
uint8_t** pData, bool ignoreFault) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
|
||||
uint8_t** pData) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId);
|
||||
if (status == returnvalue::OK) {
|
||||
*pData = &store[storageId->poolIndex][getRawPosition(*storageId)];
|
||||
} else {
|
||||
@@ -167,7 +166,7 @@ void LocalPool::clearStore() {
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId, bool ignoreFault) {
|
||||
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId) {
|
||||
ReturnValue_t status = getSubPoolIndex(size, &storeId->poolIndex);
|
||||
if (status != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -318,27 +317,3 @@ bool LocalPool::hasDataAtId(store_address_t storeId) const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) {
|
||||
return StorageManagerIF::getFreeElement(storeId, size, pData);
|
||||
}
|
||||
|
||||
ConstAccessorPair LocalPool::getData(store_address_t storeId) {
|
||||
return StorageManagerIF::getData(storeId);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storeId, const uint8_t* data, size_t size) {
|
||||
return StorageManagerIF::addData(storeId, data, size);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getData(store_address_t storeId, ConstStorageAccessor& accessor) {
|
||||
return StorageManagerIF::getData(storeId, accessor);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::modifyData(store_address_t storeId, StorageAccessor& accessor) {
|
||||
return StorageManagerIF::modifyData(storeId, accessor);
|
||||
}
|
||||
|
||||
AccessorPair LocalPool::modifyData(store_address_t storeId) {
|
||||
return StorageManagerIF::modifyData(storeId);
|
||||
}
|
||||
|
@@ -86,21 +86,13 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
/**
|
||||
* Documentation: See StorageManagerIF.h
|
||||
*/
|
||||
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) override;
|
||||
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size) override;
|
||||
|
||||
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) override;
|
||||
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData,
|
||||
bool ignoreFault) override;
|
||||
|
||||
ConstAccessorPair getData(store_address_t storeId) override;
|
||||
ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& accessor) override;
|
||||
ReturnValue_t getData(store_address_t storeId, const uint8_t** packet_ptr, size_t* size) override;
|
||||
|
||||
AccessorPair modifyData(store_address_t storeId) override;
|
||||
ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr, size_t* size) override;
|
||||
ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) override;
|
||||
|
||||
ReturnValue_t deleteData(store_address_t storeId) override;
|
||||
ReturnValue_t deleteData(uint8_t* ptr, size_t size, store_address_t* storeId) override;
|
||||
@@ -136,6 +128,12 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
[[nodiscard]] max_subpools_t getNumberOfSubPools() const override;
|
||||
[[nodiscard]] bool hasDataAtId(store_address_t storeId) const override;
|
||||
|
||||
// Using functions provided by StorageManagerIF requires either a fully qualified path
|
||||
// like for example localPool.StorageManagerIF::getFreeElement(...) or re-exporting
|
||||
// the fully qualified path with the using directive.
|
||||
using StorageManagerIF::getData;
|
||||
using StorageManagerIF::modifyData;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* With this helper method, a free element of @c size is reserved.
|
||||
@@ -144,7 +142,7 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
* @return - returnvalue::OK on success,
|
||||
* - the return codes of #getPoolIndex or #findEmpty otherwise.
|
||||
*/
|
||||
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault);
|
||||
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address);
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -188,6 +186,8 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
std::vector<std::vector<size_type>> sizeLists =
|
||||
std::vector<std::vector<size_type>>(NUMBER_OF_SUBPOOLS);
|
||||
|
||||
bool ignoreFault = false;
|
||||
|
||||
//! A variable to determine whether higher n pools are used if
|
||||
//! the store is full.
|
||||
bool spillsToHigherPools = false;
|
||||
|
@@ -9,10 +9,9 @@ PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPo
|
||||
|
||||
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
|
||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address,
|
||||
bool ignoreFault) {
|
||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
|
||||
ReturnValue_t status = LocalPool::reserveSpace(size, address, ignoreFault);
|
||||
ReturnValue_t status = LocalPool::reserveSpace(size, address);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@@ -57,7 +57,7 @@ class PoolManager : public LocalPool {
|
||||
//! Default mutex timeout value to prevent permanent blocking.
|
||||
uint32_t mutexTimeoutMs = 20;
|
||||
|
||||
ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault) override;
|
||||
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;
|
||||
|
||||
/**
|
||||
* @brief The mutex is created in the constructor and makes
|
||||
|
@@ -55,7 +55,7 @@ class StorageManagerIF {
|
||||
/**
|
||||
* @brief This is the empty virtual destructor as required for C++ interfaces.
|
||||
*/
|
||||
~StorageManagerIF() = default;
|
||||
virtual ~StorageManagerIF() = default;
|
||||
/**
|
||||
* @brief With addData, a free storage position is allocated and data
|
||||
* stored there.
|
||||
@@ -66,12 +66,7 @@ class StorageManagerIF {
|
||||
* @return Returns @returnvalue::OK if data was added.
|
||||
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
|
||||
*/
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) = 0;
|
||||
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) {
|
||||
return addData(storageId, data, size, false);
|
||||
}
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* @brief With deleteData, the storageManager frees the memory region
|
||||
@@ -186,12 +181,8 @@ class StorageManagerIF {
|
||||
* @return Returns @returnvalue::OK if data was added.
|
||||
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
|
||||
*/
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr,
|
||||
bool ignoreFault) = 0;
|
||||
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr) {
|
||||
return getFreeElement(storageId, size, dataPtr, false);
|
||||
}
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size,
|
||||
uint8_t** dataPtr) = 0;
|
||||
|
||||
[[nodiscard]] virtual bool hasDataAtId(store_address_t storeId) const = 0;
|
||||
|
||||
|
@@ -33,12 +33,8 @@ struct SequenceEntry : public TableSequenceBase {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class extends the SubsystemBase to perform the management of mode tables
|
||||
* and mode sequences
|
||||
* @brief TODO: documentation missing
|
||||
* @details
|
||||
* This class is able to use mode tables and sequences to command all its children into the
|
||||
* right mode. Fallback sequences can be used to handle failed transitions or have a fallback
|
||||
* in case a component can't keep its current mode.
|
||||
*/
|
||||
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
public:
|
||||
|
@@ -8,13 +8,11 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
|
||||
uint16_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
mode(initialMode),
|
||||
commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
|
||||
CommandMessage::MAX_MESSAGE_SIZE)),
|
||||
healthHelper(this, setObjectId),
|
||||
modeHelper(this),
|
||||
parentId(parent) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
parentId(parent) {}
|
||||
|
||||
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
@@ -33,9 +31,8 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
|
||||
info.mode = MODE_OFF;
|
||||
}
|
||||
} else {
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = child->getCommandQueue();
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
info.mode = -1; // intentional to force an initial command during system startup
|
||||
}
|
||||
|
||||
info.submode = SUBMODE_NONE;
|
||||
|
@@ -15,14 +15,7 @@
|
||||
|
||||
/**
|
||||
* @defgroup subsystems Subsystem Objects
|
||||
* All Subsystem and Assemblies can derive from this class. It contains helper classes to
|
||||
* perform mode and health handling, which allows OBSW developers to build a mode tree for
|
||||
* the whole satellite.
|
||||
*
|
||||
* Aside from setting up a mode tree and being able to executing mode tables, this class does not
|
||||
* provide an implementation on what to do with the features. To build a mode tree, helper classes
|
||||
* like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base
|
||||
* class.
|
||||
* Contains all Subsystem and Assemblies
|
||||
*/
|
||||
class SubsystemBase : public SystemObject,
|
||||
public HasModesIF,
|
||||
@@ -102,7 +95,6 @@ class SubsystemBase : public SystemObject,
|
||||
Submode_t targetSubmode);
|
||||
|
||||
/**
|
||||
* This function takes care of sending all according mode commands specified inside a mode table.
|
||||
* We need to know the target Submode, as children are able to inherit the submode
|
||||
* Still, we have a default for all child implementations which do not use submode inheritance
|
||||
*/
|
||||
|
@@ -4,13 +4,14 @@
|
||||
|
||||
AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid,
|
||||
ThermalModuleIF *thermalModule)
|
||||
: SystemObject(setObjectid), healthHelper(this, setObjectid), parameterHelper(this) {
|
||||
if (thermalModule != nullptr) {
|
||||
: SystemObject(setObjectid),
|
||||
commandQueue(NULL),
|
||||
healthHelper(this, setObjectid),
|
||||
parameterHelper(this) {
|
||||
if (thermalModule != NULL) {
|
||||
thermalModule->registerSensor(this);
|
||||
}
|
||||
auto mqArgs = MqArgs(setObjectid, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
AbstractTemperatureSensor::~AbstractTemperatureSensor() {
|
||||
|
@@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF,
|
||||
HasHealthIF::HealthState getHealth();
|
||||
|
||||
protected:
|
||||
MessageQueueIF* commandQueue = nullptr;
|
||||
MessageQueueIF* commandQueue;
|
||||
HealthHelper healthHelper;
|
||||
ParameterHelper parameterHelper;
|
||||
|
||||
|
@@ -12,9 +12,7 @@ Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1)
|
||||
switch1(switch1),
|
||||
heaterOnCountdown(10800000) /*about two orbits*/,
|
||||
parameterHelper(this) {
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue();
|
||||
}
|
||||
|
||||
Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); }
|
||||
|
@@ -13,9 +13,9 @@ class ThermalComponentIF : public HasParametersIF {
|
||||
static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW);
|
||||
static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW);
|
||||
static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW);
|
||||
//!< Is thrown when a device should start-up, but the temperature is out
|
||||
//!< of OP range. P1: thermalState of the component, P2: 0
|
||||
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW);
|
||||
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(
|
||||
5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out
|
||||
//!< of OP range. P1: thermalState of the component, P2: 0
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF;
|
||||
static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1);
|
||||
|
@@ -1,11 +1,7 @@
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
||||
if (startImmediately) {
|
||||
setTimeout(initialTimeout);
|
||||
} else {
|
||||
timeout = initialTimeout;
|
||||
}
|
||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
|
||||
setTimeout(initialTimeout);
|
||||
}
|
||||
|
||||
Countdown::~Countdown() {}
|
||||
|
@@ -26,9 +26,8 @@ class Countdown {
|
||||
* Otherwise a call to hasTimedOut might return True.
|
||||
*
|
||||
* @param initialTimeout Countdown duration in milliseconds
|
||||
* @param startImmediately Set to false if countdown should not be started immediately
|
||||
*/
|
||||
Countdown(uint32_t initialTimeout = 0, bool startImmediately = true);
|
||||
Countdown(uint32_t initialTimeout = 0);
|
||||
~Countdown();
|
||||
/**
|
||||
* Call to set a new countdown duration.
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#ifndef FSFW_TIMEMANAGER_TIMEREADERIF_H
|
||||
#define FSFW_TIMEMANAGER_TIMEREADERIF_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "fsfw/platform.h"
|
||||
|
@@ -33,47 +33,50 @@ class TmStoreBackendIF : public HasParametersIF {
|
||||
static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
|
||||
//! Initiating sending data to store failed. Low, par1:
|
||||
//! returnCode, par2: integer (debug info)
|
||||
static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
//! Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW);
|
||||
//! Initiating reading data from store failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW);
|
||||
//! Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
//! An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info)
|
||||
static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW);
|
||||
//! Storing data failed. May simply be a full store. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW);
|
||||
//! Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW);
|
||||
//! Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
|
||||
//! Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW);
|
||||
//! Data was read out, but it is inconsistent. Low par1:
|
||||
//! Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO);
|
||||
|
||||
static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW);
|
||||
//! Info event indicating the store will be initialized, either at boot or after IOB switch.
|
||||
//! Info. pars: 0
|
||||
static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO);
|
||||
//! Info event indicating the store was successfully initialized, either at boot or after
|
||||
//! IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO);
|
||||
//! Info event indicating that dumping finished successfully.
|
||||
//! par1: Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO);
|
||||
//! Info event indicating that deletion finished successfully.
|
||||
//! par1:Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO);
|
||||
//! Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW);
|
||||
//! Info that the a auto catalog report failed
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);
|
||||
static const Event STORE_SEND_WRITE_FAILED =
|
||||
MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1:
|
||||
//!< returnCode, par2: integer (debug info)
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(
|
||||
1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED =
|
||||
MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1:
|
||||
//!< returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(
|
||||
3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event UNEXPECTED_MSG =
|
||||
MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low,
|
||||
//!< par1: 0, par2: integer (debug info)
|
||||
static const Event STORING_FAILED = MAKE_EVENT(
|
||||
5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1:
|
||||
//!< returnCode, par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED =
|
||||
MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//!< par2: integer (sequence count of failed packet).
|
||||
static const Event STORE_INIT_FAILED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode,
|
||||
//!< par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(
|
||||
8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_CONTENT_CORRUPTED =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1:
|
||||
//!< Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INITIALIZE =
|
||||
MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(
|
||||
11, severity::INFO); //!< Info event indicating the store was successfully initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(
|
||||
12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1:
|
||||
//!< Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(
|
||||
13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1:
|
||||
//!< Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(
|
||||
14,
|
||||
severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED =
|
||||
MAKE_EVENT(15, severity::INFO); //!< Info that the a auto catalog report failed
|
||||
|
||||
virtual ~TmStoreBackendIF() {}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ SpacePacketReader::~SpacePacketReader() = default;
|
||||
|
||||
inline uint16_t SpacePacketReader::getPacketIdRaw() const { return ccsds::getPacketId(*spHeader); }
|
||||
|
||||
const uint8_t* SpacePacketReader::getPacketData() { return packetDataField; }
|
||||
const uint8_t* SpacePacketReader::getPacketData() const { return packetDataField; }
|
||||
|
||||
ReturnValue_t SpacePacketReader::setData(uint8_t* data, size_t maxSize_, void* args) {
|
||||
return setInternalFields(data, maxSize_);
|
||||
|
@@ -71,7 +71,7 @@ class SpacePacketReader : public SpacePacketIF,
|
||||
// Helper methods:
|
||||
[[nodiscard]] ReturnValue_t checkSize() const;
|
||||
|
||||
const uint8_t* getPacketData();
|
||||
const uint8_t* getPacketData() const;
|
||||
|
||||
ReturnValue_t setReadOnlyData(const uint8_t* data, size_t maxSize);
|
||||
|
||||
|
@@ -23,7 +23,9 @@ class AcceptsTelemetryIF {
|
||||
*/
|
||||
[[nodiscard]] virtual MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const = 0;
|
||||
|
||||
[[nodiscard]] virtual MessageQueueId_t getReportReceptionQueue() const { return getReportReceptionQueue(0); }
|
||||
[[nodiscard]] virtual MessageQueueId_t getReportReceptionQueue() const {
|
||||
return getReportReceptionQueue(0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FSFW_TMTCSERVICES_ACCEPTSTELEMETRYIF_H_ */
|
||||
|
@@ -27,10 +27,8 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a
|
||||
verificationReporter(verificationReporter),
|
||||
commandMap(numberOfParallelCommands),
|
||||
name(name) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE;
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
}
|
||||
|
||||
void CommandingServiceBase::setPacketSource(object_id_t packetSource_) {
|
||||
@@ -225,7 +223,7 @@ void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, Comma
|
||||
|
||||
// In case a new command is to be sent immediately, this is performed here.
|
||||
// If no new command is sent, only analyse reply result by initializing
|
||||
// sendResult as returnvalue::OK
|
||||
// sendResult as RETURN_OK
|
||||
ReturnValue_t sendResult = returnvalue::OK;
|
||||
if (nextCommand->getCommand() != CommandMessage::CMD_NONE) {
|
||||
sendResult = commandQueue->sendMessage(reply->getSender(), nextCommand);
|
||||
|
@@ -11,7 +11,7 @@ class SourceSequenceCounter {
|
||||
SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}
|
||||
void increment() { sequenceCount = (sequenceCount + 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
|
||||
void decrement() { sequenceCount = (sequenceCount - 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
|
||||
uint16_t get() { return this->sequenceCount; }
|
||||
uint16_t get() const { return this->sequenceCount; }
|
||||
void reset(uint16_t toValue = 0) { sequenceCount = toValue % (ccsds::LIMIT_SEQUENCE_COUNT); }
|
||||
SourceSequenceCounter& operator++(int) {
|
||||
this->increment();
|
||||
|
@@ -16,9 +16,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
|
||||
tcDestination(tcDestination)
|
||||
|
||||
{
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
||||
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
|
||||
}
|
||||
|
||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||
@@ -37,7 +35,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
|
||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) {
|
||||
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
|
||||
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
|
||||
return returnvalue::OK;
|
||||
@@ -173,18 +171,15 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
|
||||
}
|
||||
|
||||
if (tmFifo->full()) {
|
||||
if (warningSwitch) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
#endif
|
||||
warningSwitch = true;
|
||||
}
|
||||
if (overwriteOld) {
|
||||
tmFifo->retrieve(&storeId);
|
||||
tmStore->deleteData(storeId);
|
||||
|
@@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
public:
|
||||
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
|
||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 1000;
|
||||
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200;
|
||||
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||
@@ -42,7 +42,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
* @return -@c returnvalue::OK if value was set successfully
|
||||
* -@c returnvalue::FAILED otherwise, stored value stays the same
|
||||
*/
|
||||
ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored);
|
||||
ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
|
||||
|
||||
/**
|
||||
* This will set up the bridge to overwrite old data in the FIFO.
|
||||
@@ -65,15 +65,13 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
ReturnValue_t performOperation(uint8_t operationCode = 0) override;
|
||||
|
||||
/** AcceptsTelemetryIF override */
|
||||
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override;
|
||||
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override;
|
||||
|
||||
/** AcceptsTelecommandsIF override */
|
||||
uint32_t getIdentifier() const override;
|
||||
MessageQueueId_t getRequestQueue() const override;
|
||||
const char* getName() const override;
|
||||
|
||||
bool warningSwitch = true;
|
||||
|
||||
protected:
|
||||
const char* name = "";
|
||||
|
||||
@@ -154,7 +152,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
*/
|
||||
DynamicFIFO<store_address_t>* tmFifo = nullptr;
|
||||
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
||||
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||
uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */
|
||||
|
@@ -1,72 +0,0 @@
|
||||
#ifndef FSFW_UTIL_DATAWRAPPER_H
|
||||
#define FSFW_UTIL_DATAWRAPPER_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/serialize.h"
|
||||
|
||||
namespace util {
|
||||
|
||||
using BufPair = std::pair<const uint8_t*, size_t>;
|
||||
|
||||
struct RawData {
|
||||
RawData() = default;
|
||||
const uint8_t* data = nullptr;
|
||||
size_t len = 0;
|
||||
};
|
||||
|
||||
enum DataTypes { NONE, RAW, SERIALIZABLE };
|
||||
|
||||
union DataUnion {
|
||||
RawData raw{};
|
||||
SerializeIF* serializable;
|
||||
};
|
||||
|
||||
struct DataWrapper {
|
||||
DataWrapper() = default;
|
||||
|
||||
DataWrapper(const uint8_t* data, size_t size) : type(DataTypes::RAW) { setRawData({data, size}); }
|
||||
|
||||
explicit DataWrapper(BufPair raw) : type(DataTypes::RAW) { setRawData(raw); }
|
||||
|
||||
explicit DataWrapper(SerializeIF& serializable) : type(DataTypes::SERIALIZABLE) {
|
||||
setSerializable(serializable);
|
||||
}
|
||||
|
||||
DataTypes type = DataTypes::NONE;
|
||||
DataUnion dataUnion;
|
||||
|
||||
[[nodiscard]] size_t getLength() const {
|
||||
if (type == DataTypes::RAW) {
|
||||
return dataUnion.raw.len;
|
||||
} else if (type == DataTypes::SERIALIZABLE and dataUnion.serializable != nullptr) {
|
||||
return dataUnion.serializable->getSerializedSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isNull() const {
|
||||
if ((type == DataTypes::NONE) or (type == DataTypes::RAW and dataUnion.raw.data == nullptr) or
|
||||
(type == DataTypes::SERIALIZABLE and dataUnion.serializable == nullptr)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setRawData(BufPair bufPair) {
|
||||
type = DataTypes::RAW;
|
||||
dataUnion.raw.data = bufPair.first;
|
||||
dataUnion.raw.len = bufPair.second;
|
||||
}
|
||||
|
||||
void setSerializable(SerializeIF& serializable) {
|
||||
type = DataTypes::SERIALIZABLE;
|
||||
dataUnion.serializable = &serializable;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
|
||||
#endif // FSFW_UTIL_DATAWRAPPER_H
|
@@ -46,9 +46,9 @@ class GpioIF {
|
||||
* an ouput or input gpio.
|
||||
*
|
||||
* @param gpioId A unique number which specifies the GPIO to read.
|
||||
* @param gpioState State of GPIO will be written to this reference
|
||||
* @param gpioState State of GPIO will be written to this pointer.
|
||||
*/
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) = 0;
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
|
||||
};
|
||||
|
||||
#endif /* COMMON_GPIO_GPIOIF_H_ */
|
||||
|
@@ -17,7 +17,7 @@ using gpioId_t = uint16_t;
|
||||
|
||||
namespace gpio {
|
||||
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, FAILED = -1, NONE = 99 };
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
|
||||
|
||||
enum class Direction : int { IN = 0, OUT = 1 };
|
||||
|
||||
|
@@ -252,8 +252,6 @@ ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &l
|
||||
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry<float>({0.0}));
|
||||
poolManager.subscribeForRegularPeriodicPacket(
|
||||
subdp::RegularHkPeriodicParams(dataset.getSid(), false, 10.0));
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
|
@@ -371,16 +371,13 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) {
|
||||
|
||||
ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData,
|
||||
size_t commandDataLen) {
|
||||
if (commandData == nullptr) {
|
||||
return INVALID_COMMAND_PARAMETER;
|
||||
}
|
||||
triggerEvent(CHANGE_OF_SETUP_PARAMETER);
|
||||
uint32_t size = 2;
|
||||
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1);
|
||||
if (commandDataLen > 1) {
|
||||
return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
|
||||
}
|
||||
switch (commandData[0]) {
|
||||
switch (*commandData) {
|
||||
case (MGMLIS3MDL::ON): {
|
||||
commandBuffer[1] = registers[0] | (1 << 7);
|
||||
break;
|
||||
|
@@ -5,11 +5,14 @@ endif()
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE UnixFileGuard.cpp CommandExecutor.cpp
|
||||
utility.cpp)
|
||||
|
||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||
add_subdirectory(gpio)
|
||||
endif()
|
||||
if(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS)
|
||||
add_subdirectory(serial)
|
||||
endif()
|
||||
|
||||
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
||||
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||
add_subdirectory(gpio)
|
||||
endif()
|
||||
add_subdirectory(uart)
|
||||
# Adding those does not really make sense on Apple systems which are generally
|
||||
# host systems. It won't even compile as the headers are missing
|
||||
if(NOT APPLE)
|
||||
|
@@ -6,7 +6,7 @@
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
||||
UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||
std::string diagnosticPrefix)
|
||||
: fileDescriptor(fileDescriptor) {
|
||||
if (fileDescriptor == nullptr) {
|
||||
|
@@ -15,7 +15,7 @@ class UnixFileGuard {
|
||||
|
||||
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
|
||||
|
||||
UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
||||
UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||
std::string diagnosticPrefix = "");
|
||||
|
||||
virtual ~UnixFileGuard();
|
||||
|
@@ -1,27 +0,0 @@
|
||||
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
|
||||
|
||||
/**
|
||||
* @brief Additional abstraction layer for handling GPIOs.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class Gpio {
|
||||
public:
|
||||
Gpio(gpioId_t gpioId, GpioIF* gpioIF) : gpioId(gpioId), gpioIF(gpioIF) {
|
||||
if (gpioIF == nullptr) {
|
||||
sif::error << "Gpio::Gpio: Invalid GpioIF" << std::endl;
|
||||
}
|
||||
}
|
||||
ReturnValue_t pullHigh() { return gpioIF->pullHigh(gpioId); }
|
||||
ReturnValue_t pullLow() { return gpioIF->pullLow(gpioId); }
|
||||
|
||||
private:
|
||||
gpioId_t gpioId = gpio::NO_GPIO;
|
||||
GpioIF* gpioIF = nullptr;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_ */
|
@@ -214,7 +214,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl;
|
||||
@@ -244,7 +244,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl;
|
||||
@@ -294,8 +294,8 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regul
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, gpio::Levels& gpioState) {
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl;
|
||||
@@ -313,10 +313,7 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, gpio::Levels& gpioState)
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
gpioState = static_cast<gpio::Levels>(gpiod_line_get_value(regularGpio->lineHandle));
|
||||
if (gpioState == gpio::Levels::FAILED) {
|
||||
return GPIO_GET_VALUE_FAILED;
|
||||
}
|
||||
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
|
||||
} else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
if (gpioCallback->callback == nullptr) {
|
||||
@@ -377,7 +374,7 @@ ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck,
|
||||
gpio::GpioTypes expectedType,
|
||||
GpioMap& mapToAdd) {
|
||||
// Cross check with private map
|
||||
auto gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
if (gpioMapIter != gpioMap.end()) {
|
||||
auto& gpioType = gpioMapIter->second->gpioType;
|
||||
bool eraseDuplicateDifferentType = false;
|
||||
|
@@ -25,8 +25,6 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE = returnvalue::makeCode(gpioRetvalId, 4);
|
||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = returnvalue::makeCode(gpioRetvalId, 5);
|
||||
static constexpr ReturnValue_t GPIO_INIT_FAILED = returnvalue::makeCode(gpioRetvalId, 6);
|
||||
// Will be returned if getting the line value failed. Error type will be set to errno in this case
|
||||
static constexpr ReturnValue_t GPIO_GET_VALUE_FAILED = returnvalue::makeCode(gpioRetvalId, 7);
|
||||
|
||||
LinuxLibgpioIF(object_id_t objectId);
|
||||
virtual ~LinuxLibgpioIF();
|
||||
@@ -34,7 +32,7 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
|
||||
ReturnValue_t pullHigh(gpioId_t gpioId) override;
|
||||
ReturnValue_t pullLow(gpioId_t gpioId) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
|
||||
|
||||
private:
|
||||
static const size_t MAX_CHIPNAME_LENGTH = 11;
|
||||
@@ -44,6 +42,7 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
|
||||
// Holds the information and configuration of all used GPIOs
|
||||
GpioUnorderedMap gpioMap;
|
||||
GpioUnorderedMapIter gpioMapIter;
|
||||
|
||||
/**
|
||||
* @brief This functions drives line of a GPIO specified by the GPIO ID.
|
||||
|
2
src/fsfw_hal/linux/serial/CMakeLists.txt
Normal file
2
src/fsfw_hal/linux/serial/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
target_sources(${LIB_FSFW_NAME} PUBLIC SerialComIF.cpp SerialCookie.cpp
|
||||
helper.cpp)
|
@@ -1,4 +1,5 @@
|
||||
#include "UartComIF.h"
|
||||
#include "SerialComIF.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
@@ -10,18 +11,18 @@
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw_hal/linux/utility.h"
|
||||
|
||||
UartComIF::UartComIF(object_id_t objectId) : SystemObject(objectId) {}
|
||||
SerialComIF::SerialComIF(object_id_t objectId) : SystemObject(objectId) {}
|
||||
|
||||
UartComIF::~UartComIF() {}
|
||||
SerialComIF::~SerialComIF() {}
|
||||
|
||||
ReturnValue_t UartComIF::initializeInterface(CookieIF* cookie) {
|
||||
ReturnValue_t SerialComIF::initializeInterface(CookieIF* cookie) {
|
||||
std::string deviceFile;
|
||||
|
||||
if (cookie == nullptr) {
|
||||
return NULLPOINTER;
|
||||
}
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "UartComIF::initializeInterface: Invalid UART Cookie!" << std::endl;
|
||||
@@ -58,7 +59,7 @@ ReturnValue_t UartComIF::initializeInterface(CookieIF* cookie) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
int UartComIF::configureUartPort(UartCookie* uartCookie) {
|
||||
int SerialComIF::configureUartPort(SerialCookie* uartCookie) {
|
||||
struct termios options = {};
|
||||
|
||||
std::string deviceFile = uartCookie->getDeviceFile();
|
||||
@@ -87,7 +88,7 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
setParityOptions(&options, uartCookie);
|
||||
uart::setParity(options, uartCookie->getParity());
|
||||
setStopBitOptions(&options, uartCookie);
|
||||
setDatasizeOptions(&options, uartCookie);
|
||||
setFixedOptions(&options);
|
||||
@@ -113,24 +114,7 @@ int UartComIF::configureUartPort(UartCookie* uartCookie) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void UartComIF::setParityOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
/* Clear parity bit */
|
||||
options->c_cflag &= ~PARENB;
|
||||
switch (uartCookie->getParity()) {
|
||||
case Parity::EVEN:
|
||||
options->c_cflag |= PARENB;
|
||||
options->c_cflag &= ~PARODD;
|
||||
break;
|
||||
case Parity::ODD:
|
||||
options->c_cflag |= PARENB;
|
||||
options->c_cflag |= PARODD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setStopBitOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
void SerialComIF::setStopBitOptions(struct termios* options, SerialCookie* uartCookie) {
|
||||
/* Clear stop field. Sets stop bit to one bit */
|
||||
options->c_cflag &= ~CSTOPB;
|
||||
switch (uartCookie->getStopBits()) {
|
||||
@@ -142,7 +126,7 @@ void UartComIF::setStopBitOptions(struct termios* options, UartCookie* uartCooki
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCookie) {
|
||||
void SerialComIF::setDatasizeOptions(struct termios* options, SerialCookie* uartCookie) {
|
||||
/* Clear size bits */
|
||||
options->c_cflag &= ~CSIZE;
|
||||
switch (uartCookie->getBitsPerWord()) {
|
||||
@@ -166,7 +150,7 @@ void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCook
|
||||
}
|
||||
}
|
||||
|
||||
void UartComIF::setFixedOptions(struct termios* options) {
|
||||
void SerialComIF::setFixedOptions(struct termios* options) {
|
||||
/* Disable RTS/CTS hardware flow control */
|
||||
options->c_cflag &= ~CRTSCTS;
|
||||
/* Turn on READ & ignore ctrl lines (CLOCAL = 1) */
|
||||
@@ -189,7 +173,7 @@ void UartComIF::setFixedOptions(struct termios* options) {
|
||||
options->c_oflag &= ~ONLCR;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) {
|
||||
ReturnValue_t SerialComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) {
|
||||
int fd = 0;
|
||||
std::string deviceFile;
|
||||
|
||||
@@ -204,7 +188,7 @@ ReturnValue_t UartComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData,
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::sendMessasge: Invalid UART Cookie!" << std::endl;
|
||||
@@ -235,12 +219,12 @@ ReturnValue_t UartComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData,
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::getSendSuccess(CookieIF* cookie) { return returnvalue::OK; }
|
||||
ReturnValue_t SerialComIF::getSendSuccess(CookieIF* cookie) { return returnvalue::OK; }
|
||||
|
||||
ReturnValue_t UartComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) {
|
||||
ReturnValue_t SerialComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) {
|
||||
std::string deviceFile;
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "UartComIF::requestReceiveMessage: Invalid Uart Cookie!" << std::endl;
|
||||
@@ -273,8 +257,8 @@ ReturnValue_t UartComIF::requestReceiveMessage(CookieIF* cookie, size_t requestL
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
size_t requestLen) {
|
||||
ReturnValue_t SerialComIF::handleCanonicalRead(SerialCookie& uartCookie,
|
||||
UartDeviceMap::iterator& iter, size_t requestLen) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
uint8_t maxReadCycles = uartCookie.getReadCycles();
|
||||
uint8_t currentReadCycles = 0;
|
||||
@@ -331,8 +315,9 @@ ReturnValue_t UartComIF::handleCanonicalRead(UartCookie& uartCookie, UartDeviceM
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::handleNoncanonicalRead(UartCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
size_t requestLen) {
|
||||
ReturnValue_t SerialComIF::handleNoncanonicalRead(SerialCookie& uartCookie,
|
||||
UartDeviceMap::iterator& iter,
|
||||
size_t requestLen) {
|
||||
int fd = iter->second.fileDescriptor;
|
||||
auto bufferPtr = iter->second.replyBuffer.data();
|
||||
// Size check to prevent buffer overflow
|
||||
@@ -365,10 +350,10 @@ ReturnValue_t UartComIF::handleNoncanonicalRead(UartCookie& uartCookie, UartDevi
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) {
|
||||
ReturnValue_t SerialComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) {
|
||||
std::string deviceFile;
|
||||
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "UartComIF::readReceivedMessage: Invalid uart cookie!" << std::endl;
|
||||
@@ -395,9 +380,9 @@ ReturnValue_t UartComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::flushUartRxBuffer(CookieIF* cookie) {
|
||||
ReturnValue_t SerialComIF::flushUartRxBuffer(CookieIF* cookie) {
|
||||
std::string deviceFile;
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::flushUartRxBuffer: Invalid uart cookie!" << std::endl;
|
||||
@@ -414,9 +399,9 @@ ReturnValue_t UartComIF::flushUartRxBuffer(CookieIF* cookie) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::flushUartTxBuffer(CookieIF* cookie) {
|
||||
ReturnValue_t SerialComIF::flushUartTxBuffer(CookieIF* cookie) {
|
||||
std::string deviceFile;
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::flushUartTxBuffer: Invalid uart cookie!" << std::endl;
|
||||
@@ -433,9 +418,9 @@ ReturnValue_t UartComIF::flushUartTxBuffer(CookieIF* cookie) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t UartComIF::flushUartTxAndRxBuf(CookieIF* cookie) {
|
||||
ReturnValue_t SerialComIF::flushUartTxAndRxBuf(CookieIF* cookie) {
|
||||
std::string deviceFile;
|
||||
UartCookie* uartCookie = dynamic_cast<UartCookie*>(cookie);
|
||||
SerialCookie* uartCookie = dynamic_cast<SerialCookie*>(cookie);
|
||||
if (uartCookie == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::flushUartTxAndRxBuf: Invalid uart cookie!" << std::endl;
|
||||
@@ -451,5 +436,3 @@ ReturnValue_t UartComIF::flushUartTxAndRxBuf(CookieIF* cookie) {
|
||||
}
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,14 @@
|
||||
#ifndef BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||
#define BSP_Q7S_COMIF_UARTCOMIF_H_
|
||||
|
||||
#include "UartCookie.h"
|
||||
#include "helper.h"
|
||||
|
||||
#include <fsfw/devicehandlers/DeviceCommunicationIF.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw_hal/linux/serial/SerialCookie.h>
|
||||
#include <fsfw_hal/linux/serial/helper.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/**
|
||||
* @brief This is the communication interface to access serial ports on linux based operating
|
||||
* systems.
|
||||
@@ -20,7 +18,7 @@
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class UartComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
class SerialComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
public:
|
||||
static constexpr uint8_t uartRetvalId = CLASS_ID::HAL_UART;
|
||||
|
||||
@@ -28,9 +26,9 @@ class UartComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
static constexpr ReturnValue_t UART_READ_SIZE_MISSMATCH = returnvalue::makeCode(uartRetvalId, 2);
|
||||
static constexpr ReturnValue_t UART_RX_BUFFER_TOO_SMALL = returnvalue::makeCode(uartRetvalId, 3);
|
||||
|
||||
UartComIF(object_id_t objectId);
|
||||
SerialComIF(object_id_t objectId);
|
||||
|
||||
virtual ~UartComIF();
|
||||
virtual ~SerialComIF();
|
||||
|
||||
ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
|
||||
@@ -77,20 +75,9 @@ class UartComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
* uart device file, baudrate, parity, stopbits etc.
|
||||
* @return The file descriptor of the configured uart.
|
||||
*/
|
||||
int configureUartPort(UartCookie* uartCookie);
|
||||
int configureUartPort(SerialCookie* uartCookie);
|
||||
|
||||
/**
|
||||
* @brief This function adds the parity settings to the termios options struct.
|
||||
*
|
||||
* @param options Pointer to termios options struct which will be modified to enable or disable
|
||||
* parity checking.
|
||||
* @param uartCookie Pointer to uart cookie containing the information about the desired
|
||||
* parity settings.
|
||||
*
|
||||
*/
|
||||
void setParityOptions(struct termios* options, UartCookie* uartCookie);
|
||||
|
||||
void setStopBitOptions(struct termios* options, UartCookie* uartCookie);
|
||||
void setStopBitOptions(struct termios* options, SerialCookie* uartCookie);
|
||||
|
||||
/**
|
||||
* @brief This function sets options which are not configurable by the uartCookie.
|
||||
@@ -100,11 +87,11 @@ class UartComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
/**
|
||||
* @brief With this function the datasize settings are added to the termios options struct.
|
||||
*/
|
||||
void setDatasizeOptions(struct termios* options, UartCookie* uartCookie);
|
||||
void setDatasizeOptions(struct termios* options, SerialCookie* uartCookie);
|
||||
|
||||
ReturnValue_t handleCanonicalRead(UartCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
ReturnValue_t handleCanonicalRead(SerialCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
size_t requestLen);
|
||||
ReturnValue_t handleNoncanonicalRead(UartCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
ReturnValue_t handleNoncanonicalRead(SerialCookie& uartCookie, UartDeviceMap::iterator& iter,
|
||||
size_t requestLen);
|
||||
};
|
||||
|
51
src/fsfw_hal/linux/serial/SerialCookie.cpp
Normal file
51
src/fsfw_hal/linux/serial/SerialCookie.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "SerialCookie.h"
|
||||
|
||||
#include <fsfw/serviceinterface.h>
|
||||
|
||||
SerialCookie::SerialCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
|
||||
size_t maxReplyLen, UartModes uartMode)
|
||||
: handlerId(handlerId),
|
||||
deviceFile(deviceFile),
|
||||
uartMode(uartMode),
|
||||
baudrate(baudrate),
|
||||
maxReplyLen(maxReplyLen) {}
|
||||
|
||||
SerialCookie::~SerialCookie() {}
|
||||
|
||||
UartBaudRate SerialCookie::getBaudrate() const { return baudrate; }
|
||||
|
||||
size_t SerialCookie::getMaxReplyLen() const { return maxReplyLen; }
|
||||
|
||||
std::string SerialCookie::getDeviceFile() const { return deviceFile; }
|
||||
|
||||
void SerialCookie::setParityOdd() { parity = Parity::ODD; }
|
||||
|
||||
void SerialCookie::setParityEven() { parity = Parity::EVEN; }
|
||||
|
||||
Parity SerialCookie::getParity() const { return parity; }
|
||||
|
||||
void SerialCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; }
|
||||
|
||||
BitsPerWord SerialCookie::getBitsPerWord() const { return bitsPerWord; }
|
||||
|
||||
StopBits SerialCookie::getStopBits() const { return stopBits; }
|
||||
|
||||
void SerialCookie::setTwoStopBits() { stopBits = StopBits::TWO_STOP_BITS; }
|
||||
|
||||
void SerialCookie::setOneStopBit() { stopBits = StopBits::ONE_STOP_BIT; }
|
||||
|
||||
UartModes SerialCookie::getUartMode() const { return uartMode; }
|
||||
|
||||
void SerialCookie::setReadCycles(uint8_t readCycles) { this->readCycles = readCycles; }
|
||||
|
||||
void SerialCookie::setToFlushInput(bool enable) { this->flushInput = enable; }
|
||||
|
||||
uint8_t SerialCookie::getReadCycles() const { return readCycles; }
|
||||
|
||||
bool SerialCookie::getInputShouldBeFlushed() { return this->flushInput; }
|
||||
|
||||
object_id_t SerialCookie::getHandlerId() const { return this->handlerId; }
|
||||
|
||||
void SerialCookie::setNoFixedSizeReply() { replySizeFixed = false; }
|
||||
|
||||
bool SerialCookie::isReplySizeFixed() { return replySizeFixed; }
|
@@ -1,15 +1,12 @@
|
||||
#ifndef SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||
#define SAM9G20_COMIF_COOKIES_UART_COOKIE_H_
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <fsfw_hal/linux/serial/helper.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cookie for the UartComIF. There are many options available to configure the UART driver.
|
||||
* The constructor only requests for common options like the baudrate. Other options can
|
||||
@@ -17,7 +14,7 @@
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class UartCookie : public CookieIF {
|
||||
class SerialCookie : public CookieIF {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for the uart cookie.
|
||||
@@ -32,10 +29,10 @@ class UartCookie : public CookieIF {
|
||||
* 8 databits (number of bits transfered with one uart frame)
|
||||
* One stop bit
|
||||
*/
|
||||
UartCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
|
||||
size_t maxReplyLen, UartModes uartMode = UartModes::NON_CANONICAL);
|
||||
SerialCookie(object_id_t handlerId, std::string deviceFile, UartBaudRate baudrate,
|
||||
size_t maxReplyLen, UartModes uartMode = UartModes::NON_CANONICAL);
|
||||
|
||||
virtual ~UartCookie();
|
||||
virtual ~SerialCookie();
|
||||
|
||||
UartBaudRate getBaudrate() const;
|
||||
size_t getMaxReplyLen() const;
|
163
src/fsfw_hal/linux/serial/helper.cpp
Normal file
163
src/fsfw_hal/linux/serial/helper.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include <fsfw_hal/linux/serial/helper.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
void uart::setMode(struct termios& options, UartModes mode) {
|
||||
if (mode == UartModes::NON_CANONICAL) {
|
||||
/* Disable canonical mode */
|
||||
options.c_lflag &= ~ICANON;
|
||||
} else if (mode == UartModes::CANONICAL) {
|
||||
options.c_lflag |= ICANON;
|
||||
}
|
||||
}
|
||||
|
||||
void uart::setBaudrate(struct termios& options, UartBaudRate baud) {
|
||||
switch (baud) {
|
||||
case UartBaudRate::RATE_50:
|
||||
cfsetspeed(&options, B50);
|
||||
break;
|
||||
case UartBaudRate::RATE_75:
|
||||
cfsetspeed(&options, B75);
|
||||
break;
|
||||
case UartBaudRate::RATE_110:
|
||||
cfsetspeed(&options, B110);
|
||||
break;
|
||||
case UartBaudRate::RATE_134:
|
||||
cfsetspeed(&options, B134);
|
||||
break;
|
||||
case UartBaudRate::RATE_150:
|
||||
cfsetspeed(&options, B150);
|
||||
break;
|
||||
case UartBaudRate::RATE_200:
|
||||
cfsetspeed(&options, B200);
|
||||
break;
|
||||
case UartBaudRate::RATE_300:
|
||||
cfsetspeed(&options, B300);
|
||||
break;
|
||||
case UartBaudRate::RATE_600:
|
||||
cfsetspeed(&options, B600);
|
||||
break;
|
||||
case UartBaudRate::RATE_1200:
|
||||
cfsetspeed(&options, B1200);
|
||||
break;
|
||||
case UartBaudRate::RATE_1800:
|
||||
cfsetspeed(&options, B1800);
|
||||
break;
|
||||
case UartBaudRate::RATE_2400:
|
||||
cfsetspeed(&options, B2400);
|
||||
break;
|
||||
case UartBaudRate::RATE_4800:
|
||||
cfsetspeed(&options, B4800);
|
||||
break;
|
||||
case UartBaudRate::RATE_9600:
|
||||
cfsetspeed(&options, B9600);
|
||||
break;
|
||||
case UartBaudRate::RATE_19200:
|
||||
cfsetspeed(&options, B19200);
|
||||
break;
|
||||
case UartBaudRate::RATE_38400:
|
||||
cfsetspeed(&options, B38400);
|
||||
break;
|
||||
case UartBaudRate::RATE_57600:
|
||||
cfsetspeed(&options, B57600);
|
||||
break;
|
||||
case UartBaudRate::RATE_115200:
|
||||
cfsetspeed(&options, B115200);
|
||||
break;
|
||||
case UartBaudRate::RATE_230400:
|
||||
cfsetspeed(&options, B230400);
|
||||
break;
|
||||
#ifndef __APPLE__
|
||||
case UartBaudRate::RATE_460800:
|
||||
cfsetspeed(&options, B460800);
|
||||
break;
|
||||
case UartBaudRate::RATE_500000:
|
||||
cfsetspeed(&options, B500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_576000:
|
||||
cfsetspeed(&options, B576000);
|
||||
break;
|
||||
case UartBaudRate::RATE_921600:
|
||||
cfsetspeed(&options, B921600);
|
||||
break;
|
||||
case UartBaudRate::RATE_1000000:
|
||||
cfsetspeed(&options, B1000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_1152000:
|
||||
cfsetspeed(&options, B1152000);
|
||||
break;
|
||||
case UartBaudRate::RATE_1500000:
|
||||
cfsetspeed(&options, B1500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_2000000:
|
||||
cfsetspeed(&options, B2000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_2500000:
|
||||
cfsetspeed(&options, B2500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_3000000:
|
||||
cfsetspeed(&options, B3000000);
|
||||
break;
|
||||
case UartBaudRate::RATE_3500000:
|
||||
cfsetspeed(&options, B3500000);
|
||||
break;
|
||||
case UartBaudRate::RATE_4000000:
|
||||
cfsetspeed(&options, B4000000);
|
||||
break;
|
||||
#endif // ! __APPLE__
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void uart::setBitsPerWord(struct termios& options, BitsPerWord bits) {
|
||||
options.c_cflag &= ~CSIZE; // Clear all the size bits
|
||||
if (bits == BitsPerWord::BITS_5) {
|
||||
options.c_cflag |= CS5;
|
||||
} else if (bits == BitsPerWord::BITS_6) {
|
||||
options.c_cflag |= CS6;
|
||||
} else if (bits == BitsPerWord::BITS_7) {
|
||||
options.c_cflag |= CS7;
|
||||
} else if (bits == BitsPerWord::BITS_8) {
|
||||
options.c_cflag |= CS8;
|
||||
}
|
||||
}
|
||||
|
||||
void uart::enableRead(struct termios& options) { options.c_cflag |= CREAD; }
|
||||
|
||||
void uart::ignoreCtrlLines(struct termios& options) { options.c_cflag |= CLOCAL; }
|
||||
|
||||
void uart::setParity(struct termios& options, Parity parity) {
|
||||
/* Clear parity bit */
|
||||
options.c_cflag &= ~PARENB;
|
||||
switch (parity) {
|
||||
case Parity::EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
case Parity::ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int uart::readCountersAndErrors(int serialPort, serial_icounter_struct& icounter) {
|
||||
return ioctl(serialPort, TIOCGICOUNT, &icounter);
|
||||
}
|
||||
|
||||
void uart::setStopbits(struct termios& options, StopBits bits) {
|
||||
if (bits == StopBits::TWO_STOP_BITS) {
|
||||
// Use two stop bits
|
||||
options.c_cflag |= CSTOPB;
|
||||
} else {
|
||||
// Clear stop field, only one stop bit used in communication
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
#ifndef FSFW_HAL_LINUX_UART_HELPER_H_
|
||||
#define FSFW_HAL_LINUX_UART_HELPER_H_
|
||||
|
||||
#include <termios.h>
|
||||
#include <linux/serial.h>
|
||||
#include <termios.h>
|
||||
|
||||
enum class Parity { NONE, EVEN, ODD };
|
||||
|
||||
@@ -54,9 +54,18 @@ void setMode(struct termios& options, UartModes mode);
|
||||
*/
|
||||
void setBaudrate(struct termios& options, UartBaudRate baud);
|
||||
|
||||
void setStopbits(struct termios& options, StopBits bits);
|
||||
|
||||
void setBitsPerWord(struct termios& options, BitsPerWord bits);
|
||||
|
||||
void enableRead(struct termios& options);
|
||||
|
||||
void setParity(struct termios& options, Parity parity);
|
||||
|
||||
void ignoreCtrlLines(struct termios& options);
|
||||
|
||||
int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter);
|
||||
|
||||
}
|
||||
|
||||
} // namespace uart
|
||||
|
||||
#endif /* FSFW_HAL_LINUX_UART_HELPER_H_ */
|
@@ -1,43 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/ipc/MutexIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
|
||||
class ManualCsLockWrapper {
|
||||
public:
|
||||
ManualCsLockWrapper(MutexIF* lock, GpioIF* gpioIF, SpiCookie* cookie,
|
||||
MutexIF::TimeoutType type = MutexIF::TimeoutType::BLOCKING,
|
||||
uint32_t timeoutMs = 0)
|
||||
: lock(lock), gpioIF(gpioIF), cookie(cookie), type(type), timeoutMs(timeoutMs) {
|
||||
if (cookie == nullptr) {
|
||||
// TODO: Error? Or maybe throw exception..
|
||||
return;
|
||||
}
|
||||
cookie->setCsLockManual(true);
|
||||
lockResult = lock->lockMutex(type, timeoutMs);
|
||||
if (lockResult != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
gpioResult = gpioIF->pullLow(cookie->getChipSelectPin());
|
||||
}
|
||||
|
||||
~ManualCsLockWrapper() {
|
||||
if (gpioResult == returnvalue::OK) {
|
||||
gpioIF->pullHigh(cookie->getChipSelectPin());
|
||||
}
|
||||
cookie->setCsLockManual(false);
|
||||
if (lockResult == returnvalue::OK) {
|
||||
lock->unlockMutex();
|
||||
}
|
||||
}
|
||||
ReturnValue_t lockResult;
|
||||
ReturnValue_t gpioResult;
|
||||
|
||||
private:
|
||||
MutexIF* lock;
|
||||
GpioIF* gpioIF;
|
||||
SpiCookie* cookie;
|
||||
MutexIF::TimeoutType type;
|
||||
uint32_t timeoutMs = 0;
|
||||
};
|
@@ -15,9 +15,19 @@
|
||||
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
||||
#include "fsfw_hal/linux/utility.h"
|
||||
|
||||
SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF& gpioComIF)
|
||||
: SystemObject(objectId), gpioComIF(gpioComIF), dev(std::move(devname)) {
|
||||
csMutex = MutexFactory::instance()->createMutex();
|
||||
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
|
||||
: SystemObject(objectId), gpioComIF(gpioComIF) {
|
||||
if (gpioComIF == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::SpiComIF: GPIO communication interface invalid!" << std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::SpiComIF: GPIO communication interface invalid!\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
}
|
||||
|
||||
spiMutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
@@ -65,7 +75,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
/* Pull CS high in any case to be sure that device is inactive */
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
}
|
||||
|
||||
uint32_t spiSpeed = 0;
|
||||
@@ -75,7 +85,8 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
|
||||
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
|
||||
UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
|
||||
"SpiComIF::initializeInterface");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return fileHelper.getOpenResult();
|
||||
}
|
||||
@@ -171,7 +182,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
int retval = 0;
|
||||
/* Prepare transfer */
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return OPENING_FILE_FAILED;
|
||||
}
|
||||
@@ -184,28 +196,21 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
|
||||
bool fullDuplex = spiCookie->isFullDuplex();
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
bool csLockManual = spiCookie->getCsLockManual();
|
||||
|
||||
MutexIF::TimeoutType csType;
|
||||
dur_millis_t csTimeout = 0;
|
||||
// Pull SPI CS low. For now, no support for active high given
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
spiCookie->getMutexParams(csType, csTimeout);
|
||||
result = csMutex->lockMutex(csType, csTimeout);
|
||||
/* Pull SPI CS low. For now, no support for active high given */
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
|
||||
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
|
||||
<< std::endl;
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n");
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
updateLinePolarity(fileDescriptor);
|
||||
result = gpioComIF.pullLow(gpioId);
|
||||
result = gpioComIF->pullLow(gpioId);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -216,8 +221,6 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
updateLinePolarity(fileDescriptor);
|
||||
}
|
||||
|
||||
/* Execute transfer */
|
||||
@@ -245,9 +248,9 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
}
|
||||
}
|
||||
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
result = csMutex->unlockMutex();
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
||||
@@ -275,8 +278,9 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
||||
|
||||
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return OPENING_FILE_FAILED;
|
||||
}
|
||||
@@ -288,26 +292,16 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool csLockManual = spiCookie->getCsLockManual();
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
MutexIF::TimeoutType csType;
|
||||
dur_millis_t csTimeout = 0;
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
spiCookie->getMutexParams(csType, csTimeout);
|
||||
result = csMutex->lockMutex(csType, csTimeout);
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
|
||||
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
|
||||
#endif
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
gpioComIF.pullLow(gpioId);
|
||||
gpioComIF->pullLow(gpioId);
|
||||
}
|
||||
|
||||
if (read(fileDescriptor, rxBuf, readSize) != static_cast<ssize_t>(readSize)) {
|
||||
@@ -321,9 +315,9 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
result = HALF_DUPLEX_TRANSFER_FAILED;
|
||||
}
|
||||
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
result = csMutex->unlockMutex();
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
||||
@@ -352,7 +346,15 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
MutexIF* SpiComIF::getCsMutex() { return csMutex; }
|
||||
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
|
||||
if (timeoutType != nullptr) {
|
||||
*timeoutType = this->timeoutType;
|
||||
}
|
||||
if (timeoutMs != nullptr) {
|
||||
*timeoutMs = this->timeoutMs;
|
||||
}
|
||||
return spiMutex;
|
||||
}
|
||||
|
||||
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
||||
if (spiCookie == nullptr) {
|
||||
@@ -387,7 +389,7 @@ ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
GpioIF& SpiComIF::getGpioInterface() { return gpioComIF; }
|
||||
GpioIF* SpiComIF::getGpioInterface() { return gpioComIF; }
|
||||
|
||||
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
||||
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
||||
@@ -399,27 +401,11 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||
}
|
||||
}
|
||||
|
||||
void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const {
|
||||
uint8_t tmpMode = 0;
|
||||
int retval = ioctl(spiFd, SPI_IOC_RD_MODE, &tmpMode);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Reading SPI mode failed");
|
||||
}
|
||||
mode = static_cast<spi::SpiModes>(tmpMode);
|
||||
|
||||
retval = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Getting SPI speed failed");
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& SpiComIF::getSpiDev() const { return dev; }
|
||||
|
||||
void SpiComIF::updateLinePolarity(int spiFd) {
|
||||
// This updates the SPI clock default polarity. Only setting the mode does not update
|
||||
// the line state, which can be an issue on mode switches because the clock line will
|
||||
// switch the state after the chip select is pulled low
|
||||
clockUpdateTransfer.len = 0;
|
||||
int retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
|
||||
returnvalue::makeCode(spiRetvalId, 2);
|
||||
|
||||
SpiComIF(object_id_t objectId, std::string devname, GpioIF& gpioComIF);
|
||||
SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
|
||||
|
||||
ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
|
||||
@@ -43,8 +43,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
* @brief This function returns the mutex which can be used to protect the spi bus when
|
||||
* the chip select must be driven from outside of the com if.
|
||||
*/
|
||||
MutexIF* getCsMutex();
|
||||
void setMutexParams(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
|
||||
|
||||
/**
|
||||
* Perform a regular send operation using Linux iotcl. This is public so it can be used
|
||||
@@ -57,22 +56,8 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
|
||||
GpioIF& getGpioInterface();
|
||||
GpioIF* getGpioInterface();
|
||||
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
||||
void getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const;
|
||||
|
||||
/**
|
||||
* This updates the SPI clock default polarity. Only setting the mode does not update
|
||||
* the line state, which can be an issue on mode switches because the clock line will
|
||||
* switch the state after the chip select is pulled low.
|
||||
*
|
||||
* It is recommended to call this function after #setSpiSpeedAndMode and after locking the
|
||||
* CS mutex if the SPI bus has multiple SPI devices with different speed and SPI modes attached.
|
||||
* @param spiFd
|
||||
*/
|
||||
void updateLinePolarity(int spiFd);
|
||||
|
||||
const std::string& getSpiDev() const;
|
||||
void performSpiWiretapping(SpiCookie* spiCookie);
|
||||
|
||||
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
|
||||
@@ -83,15 +68,11 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
std::vector<uint8_t> replyBuffer;
|
||||
};
|
||||
|
||||
GpioIF& gpioComIF;
|
||||
std::string dev = "";
|
||||
/**
|
||||
* Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was
|
||||
* pulled high
|
||||
*/
|
||||
MutexIF* csMutex = nullptr;
|
||||
// MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
// uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT;
|
||||
GpioIF* gpioComIF = nullptr;
|
||||
|
||||
MutexIF* spiMutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
spi_ioc_transfer clockUpdateTransfer = {};
|
||||
|
||||
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
||||
|
@@ -1,25 +1,26 @@
|
||||
#include "SpiCookie.h"
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||
spiSpeed, nullptr, nullptr) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
||||
nullptr, nullptr) {}
|
||||
: SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed)
|
||||
: SpiCookie(spiAddress, gpio::NO_GPIO, maxSize, spiMode, spiSpeed) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args)
|
||||
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
||||
callback, args) {}
|
||||
|
||||
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args)
|
||||
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||
spiSpeed, callback, args) {}
|
||||
|
||||
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args)
|
||||
: spiAddress(spiAddress),
|
||||
chipSelectPin(chipSelect),
|
||||
spiDevice(spiDev),
|
||||
comIfMode(comIfMode),
|
||||
maxSize(maxSize),
|
||||
spiMode(spiMode),
|
||||
@@ -49,6 +50,8 @@ size_t SpiCookie::getMaxBufferSize() const { return maxSize; }
|
||||
|
||||
address_t SpiCookie::getSpiAddress() const { return spiAddress; }
|
||||
|
||||
std::string SpiCookie::getSpiDevice() const { return spiDevice; }
|
||||
|
||||
void SpiCookie::setThreeWireSpi(bool enable) { uncommonParameters.threeWireSpi = enable; }
|
||||
|
||||
void SpiCookie::setLsbFirst(bool enable) { uncommonParameters.lsbFirst = enable; }
|
||||
@@ -104,17 +107,3 @@ void SpiCookie::getCallback(spi::send_callback_function_t* callback, void** args
|
||||
*callback = this->sendCallback;
|
||||
*args = this->callbackArgs;
|
||||
}
|
||||
|
||||
void SpiCookie::setCsLockManual(bool enable) { manualCsLock = enable; }
|
||||
|
||||
bool SpiCookie::getCsLockManual() const { return manualCsLock; }
|
||||
|
||||
void SpiCookie::getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const {
|
||||
csTimeoutType = this->csTimeoutType;
|
||||
csTimeout = this->csTimeout;
|
||||
}
|
||||
|
||||
void SpiCookie::setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout) {
|
||||
this->csTimeoutType = csTimeoutType;
|
||||
this->csTimeout = csTimeout;
|
||||
}
|
||||
|
@@ -2,8 +2,6 @@
|
||||
#define LINUX_SPI_SPICOOKIE_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw/ipc/MutexIF.h>
|
||||
#include <fsfw/timemanager/clockDefinitions.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#include "../../common/gpio/gpioDefinitions.h"
|
||||
@@ -22,8 +20,6 @@
|
||||
*/
|
||||
class SpiCookie : public CookieIF {
|
||||
public:
|
||||
static constexpr dur_millis_t DEFAULT_MUTEX_TIMEOUT = 20;
|
||||
|
||||
/**
|
||||
* Each SPI device will have a corresponding cookie. The cookie is used by the communication
|
||||
* interface and contains device specific information like the largest expected size to be
|
||||
@@ -33,22 +29,23 @@ class SpiCookie : public CookieIF {
|
||||
* @param spiDev
|
||||
* @param maxSize
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed);
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
|
||||
* slave select or if CS logic is performed with decoders.
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, const size_t maxReplySize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed);
|
||||
SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Use the callback mode of the SPI communication interface. The user can pass the callback
|
||||
* function here or by using the setter function #setCallbackMode
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args);
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
|
||||
void* args);
|
||||
|
||||
/**
|
||||
* Get the callback function
|
||||
@@ -58,6 +55,7 @@ class SpiCookie : public CookieIF {
|
||||
void getCallback(spi::send_callback_function_t* callback, void** args);
|
||||
|
||||
address_t getSpiAddress() const;
|
||||
std::string getSpiDevice() const;
|
||||
gpioId_t getChipSelectPin() const;
|
||||
size_t getMaxBufferSize() const;
|
||||
|
||||
@@ -141,42 +139,9 @@ class SpiCookie : public CookieIF {
|
||||
*/
|
||||
void activateCsDeselect(bool deselectCs, uint16_t delayUsecs);
|
||||
|
||||
void getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const;
|
||||
void setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout);
|
||||
|
||||
void setCsLockManual(bool enable);
|
||||
bool getCsLockManual() const;
|
||||
|
||||
spi_ioc_transfer* getTransferStructHandle();
|
||||
|
||||
private:
|
||||
address_t spiAddress;
|
||||
gpioId_t chipSelectPin;
|
||||
|
||||
spi::SpiComIfModes comIfMode;
|
||||
|
||||
// Required for regular mode
|
||||
const size_t maxSize;
|
||||
spi::SpiModes spiMode;
|
||||
/**
|
||||
* If this is set to true, the SPI ComIF will not perform any mutex locking for the
|
||||
* CS mechanism. The user is responsible to locking and unlocking the mutex for the
|
||||
* whole duration of the transfers.
|
||||
*/
|
||||
bool manualCsLock = false;
|
||||
uint32_t spiSpeed;
|
||||
bool halfDuplex = false;
|
||||
|
||||
MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::WAITING;
|
||||
dur_millis_t csTimeout = DEFAULT_MUTEX_TIMEOUT;
|
||||
|
||||
// Required for callback mode
|
||||
spi::send_callback_function_t sendCallback = nullptr;
|
||||
void* callbackArgs = nullptr;
|
||||
|
||||
struct spi_ioc_transfer spiTransferStruct = {};
|
||||
UncommonParameters uncommonParameters;
|
||||
|
||||
/**
|
||||
* Internal constructor which initializes every field
|
||||
* @param spiAddress
|
||||
@@ -189,8 +154,27 @@ class SpiCookie : public CookieIF {
|
||||
* @param args
|
||||
*/
|
||||
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args);
|
||||
|
||||
address_t spiAddress;
|
||||
gpioId_t chipSelectPin;
|
||||
std::string spiDevice;
|
||||
|
||||
spi::SpiComIfModes comIfMode;
|
||||
|
||||
// Required for regular mode
|
||||
const size_t maxSize;
|
||||
spi::SpiModes spiMode;
|
||||
uint32_t spiSpeed;
|
||||
bool halfDuplex = false;
|
||||
|
||||
// Required for callback mode
|
||||
spi::send_callback_function_t sendCallback = nullptr;
|
||||
void* callbackArgs = nullptr;
|
||||
|
||||
struct spi_ioc_transfer spiTransferStruct = {};
|
||||
UncommonParameters uncommonParameters;
|
||||
};
|
||||
|
||||
#endif /* LINUX_SPI_SPICOOKIE_H_ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user