Compare commits
235 Commits
Author | SHA1 | Date | |
---|---|---|---|
70f0a72f1b | |||
b5d890eedd | |||
50b1b48678 | |||
0e0dbc74aa | |||
8c34051d8b | |||
b00d83cb1a | |||
17e609c3a5 | |||
64f0166b64 | |||
c80f06fbcb | |||
e796f82203 | |||
5b7ca8c13c | |||
031739ef51 | |||
b8516b15cb | |||
ac5a54b5da | |||
29015b340b | |||
64274acbeb | |||
ff98c42514 | |||
126ac52975 | |||
70d3197212 | |||
dd90980520 | |||
352ab43c1f | |||
97e98eae24 | |||
5ac88f2b15 | |||
b03a6684f9 | |||
7c2e50b665 | |||
c04ca704d2 | |||
6aa54fe1d4 | |||
c55925959b | |||
4f0669c574 | |||
f0d996ffd2 | |||
f4d05c2c9c | |||
d1151ca707 | |||
82f46992f6 | |||
c0f80680ef | |||
7761b66fe2 | |||
acc4c8d975 | |||
fe739aa81a | |||
afe006e234 | |||
95f018a0b0 | |||
8c2105ae0a | |||
ed2c2af4a0 | |||
17771c0497 | |||
82df132e7d | |||
a02619e5a2 | |||
a011e70665 | |||
c05184e1c4 | |||
b2252bdc0b | |||
7e61ce1ed2 | |||
fcb6437388 | |||
6c1db8473b | |||
1a530633ca | |||
8037e8074b | |||
d07e0e5576 | |||
5525466b52 | |||
c2a89bf709 | |||
8dd0b2608d | |||
05495077ec | |||
8ff9eadf30 | |||
082c86ea18 | |||
2800d6f28c | |||
b4effe7a46 | |||
e6e71436c2 | |||
4be45adae6 | |||
a887f852c8 | |||
0d7d2203d2 | |||
cde184f428 | |||
0b3255e463 | |||
df3794dfd8 | |||
d02d5c351d | |||
631a531212 | |||
febecd4b30 | |||
964e311d8b | |||
d43caa8296 | |||
916ed3f56a | |||
665d8cd479 | |||
10398855a9 | |||
d0fec93dc3 | |||
59ab54b2fb | |||
7095999bd2 | |||
7ffb4107d2 | |||
d9d9a28ef8 | |||
d95582b81b | |||
c60aa68d00 | |||
9ce59d3c75 | |||
a0dfdfab2c | |||
3e17011087 | |||
f441505476 | |||
7c64797f03 | |||
e08bdd3e35 | |||
d2dd16aef3 | |||
b7a617dab3 | |||
bc95e7c886 | |||
fca43b3d34 | |||
48c5c3fbd5 | |||
b694aea100 | |||
6998626ad4 | |||
24ad858b64 | |||
288d453978 | |||
522cbc7f3d | |||
ce5bcc5897 | |||
97c93afeff | |||
8704b9ab06 | |||
5a1585bd00 | |||
5d6de90859 | |||
378c6c8006 | |||
f4922a8686 | |||
0bdcb40609 | |||
e684680d60 | |||
aa5d1042f0 | |||
14ac852b7e | |||
6b1a81ee92 | |||
3779b44813 | |||
949549178a | |||
7daa9812ff | |||
ca508bfe61 | |||
345a799031 | |||
445d5dd6f0 | |||
238baa8597 | |||
7932afc315 | |||
d1e3dc4d49 | |||
77e5fba7fd | |||
ca70c8c614 | |||
14620fdd72 | |||
89c1878622 | |||
d6856fc54a | |||
e5a9cab34e | |||
a4f97a7ba7 | |||
8b1af232c3 | |||
983fa346b3 | |||
32f420c4f0 | |||
41a82e923c | |||
5ddac36314 | |||
d06eecf9b0 | |||
5912ddd2a2 | |||
7db11588b4 | |||
c88b931ef1 | |||
10ffa2f44a | |||
dbe31dd339 | |||
14b44f8bb2 | |||
117747970d | |||
c6540650e2 | |||
f659f13759 | |||
95078e1103 | |||
8920255565 | |||
2d12618c96 | |||
68ca6fd122 | |||
33e9592659 | |||
19d217e3b9 | |||
af286d3bc6 | |||
20928732ec | |||
a8426750f2 | |||
2635f39344 | |||
89327463e3 | |||
cf45eca100 | |||
c0fa365f8f | |||
9d9f19781d | |||
f4520ea346 | |||
bbacdc5cac | |||
a6c0f3fef5 | |||
0e8328fca3 | |||
1ef3dae72e | |||
32381a7872 | |||
09815f5cce | |||
f6357b4531 | |||
a10e5c6ed4 | |||
d6d13eec95 | |||
457bc6609e | |||
e75155c329 | |||
d4e48006f2 | |||
d6508e23b6 | |||
2cb254a556 | |||
f99f5ed730 | |||
5f7e384442 | |||
56d0c8c616 | |||
5ff0f8ea10 | |||
fdc8a3d4f7 | |||
e5e85bcff9 | |||
4862edfdb5 | |||
a50b52df51 | |||
eac7e6db07 | |||
0c4835bfb5 | |||
aebd4817b8 | |||
9c2ceb4a9f | |||
68ace0b74a | |||
d119479c0a | |||
6739890d53 | |||
90b8ad1e6d | |||
025f79fcb4 | |||
6fb64f9ada | |||
2f1b923009 | |||
45ea09291a | |||
b7f3eff742 | |||
a274d6598e | |||
c3d78120ea | |||
f24de22e9b | |||
918783774f | |||
6744a55b9b | |||
a612fb446c | |||
a5adeb333c | |||
7788cada54 | |||
074ef29b86 | |||
d4f059d639 | |||
22bc300902 | |||
0d38ac62d8 | |||
d81257a91c | |||
d53c7e1190 | |||
e312cd094a | |||
9e958e752e | |||
3bcd71598d | |||
2602d4fed1 | |||
805538ec6e | |||
120750f22a | |||
9897f51307 | |||
4f87e24f60 | |||
2dcf896cca | |||
cdf2a90f90 | |||
b25555a533 | |||
bc0100ee08 | |||
c6d152a01d | |||
f4f1174849 | |||
9df8722c10 | |||
a4f57a38fa | |||
6dc34fc1f0 | |||
c7b9df5e40 | |||
7b8019c621 | |||
baddbf7340 | |||
80a610141a | |||
1b41153ee6 | |||
f08d291e3e | |||
348274c145 | |||
40329a33b2 | |||
2d52042ed6 | |||
79936a3335 | |||
51add8a8ad | |||
ad5bb4c694 |
175
CHANGELOG
175
CHANGELOG
@ -1,175 +0,0 @@
|
|||||||
# Changed from ASTP 1.1.0 to 1.2.0
|
|
||||||
|
|
||||||
## API Changes
|
|
||||||
|
|
||||||
### FSFW Architecture
|
|
||||||
|
|
||||||
- New src folder which contains all source files except the HAL, contributed code and test code
|
|
||||||
- External and internal API mostly stayed the same
|
|
||||||
- Folder names are now all smaller case: internalError was renamed to internalerror and
|
|
||||||
FreeRTOS was renamed to freertos
|
|
||||||
- Warning if optional headers are used but the modules was not added to the source files to compile
|
|
||||||
|
|
||||||
### HAL
|
|
||||||
|
|
||||||
- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library
|
|
||||||
made using it more complicated than necessary
|
|
||||||
|
|
||||||
## Bugfixes
|
|
||||||
|
|
||||||
### FreeRTOS QueueMapManager
|
|
||||||
|
|
||||||
- Fixed a bug which causes the first generated Queue ID to be invalid
|
|
||||||
|
|
||||||
## Enhancements
|
|
||||||
|
|
||||||
### FSFW Architecture
|
|
||||||
|
|
||||||
- See API changes chapter. This change will keep the internal API consistent in the future
|
|
||||||
|
|
||||||
# Changes from ASTP 1.0.0 to 1.1.0
|
|
||||||
|
|
||||||
## API Changes
|
|
||||||
|
|
||||||
### PUS
|
|
||||||
|
|
||||||
- Added PUS C support
|
|
||||||
- SUBSYSTEM_IDs added for PUS Services
|
|
||||||
- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE
|
|
||||||
|
|
||||||
### ObjectManager
|
|
||||||
|
|
||||||
- ObjectManager is now a singelton
|
|
||||||
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
|
|
||||||
need to be specified in FSFWConfig.h
|
|
||||||
|
|
||||||
### CMake
|
|
||||||
|
|
||||||
- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS
|
|
||||||
|
|
||||||
## Bugfixes
|
|
||||||
|
|
||||||
- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE
|
|
||||||
- TCP server fixes
|
|
||||||
|
|
||||||
## Enhancements
|
|
||||||
|
|
||||||
### FreeRTOS Queue Handles
|
|
||||||
|
|
||||||
- Fixed an internal issue how FreeRTOS MessageQueues were handled
|
|
||||||
|
|
||||||
### Linux OSAL
|
|
||||||
|
|
||||||
- Better printf error messages
|
|
||||||
|
|
||||||
### CMake
|
|
||||||
|
|
||||||
- Check for C++11 as mininimum required Version
|
|
||||||
|
|
||||||
### Debug Output
|
|
||||||
|
|
||||||
- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs
|
|
||||||
|
|
||||||
|
|
||||||
# Changes from ASTP 0.0.1 to 1.0.0
|
|
||||||
|
|
||||||
### Host OSAL
|
|
||||||
|
|
||||||
- Bugfix in MessageQueue, which caused the sender not to be set properly
|
|
||||||
|
|
||||||
### FreeRTOS OSAL
|
|
||||||
|
|
||||||
- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in
|
|
||||||
a C file without issues
|
|
||||||
|
|
||||||
### PUS Services
|
|
||||||
|
|
||||||
- It is now possible to change the message queue depth for the telecommand verification service (PUS1)
|
|
||||||
- The same is possible for the event reporting service (PUS5)
|
|
||||||
- PUS Health Service added, which allows to command and retrieve health via PUS packets
|
|
||||||
|
|
||||||
|
|
||||||
### EnhancedControllerBase
|
|
||||||
|
|
||||||
- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF
|
|
||||||
|
|
||||||
### Local Pool
|
|
||||||
|
|
||||||
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
|
|
||||||
bucket number of the pools per page and the number of pages are passed to the ctor instead of
|
|
||||||
two ctor arguments and a template parameter
|
|
||||||
|
|
||||||
### Parameter Service
|
|
||||||
|
|
||||||
- The API of the parameter service has been changed to prevent inconsistencies
|
|
||||||
between documentation and actual code and to clarify usage.
|
|
||||||
- The parameter ID now consists of:
|
|
||||||
1. Domain ID (1 byte)
|
|
||||||
2. Unique Identifier (1 byte)
|
|
||||||
3. Linear Index (2 bytes)
|
|
||||||
The linear index can be used for arrays as well as matrices.
|
|
||||||
The parameter load command now explicitely expects the ECSS PTC and PFC
|
|
||||||
information as well as the rows and column number. Rows and column will
|
|
||||||
default to one, which is equivalent to one scalar parameter (the most
|
|
||||||
important use-case)
|
|
||||||
|
|
||||||
### File System Interface
|
|
||||||
|
|
||||||
- A new interfaces specifies the functions for a software object which exposes the file system of
|
|
||||||
a given hardware to use message based file handling (e.g. PUS commanding)
|
|
||||||
|
|
||||||
### Internal Error Reporter
|
|
||||||
|
|
||||||
- The new internal error reporter uses the local data pools. The pool IDs for
|
|
||||||
the exisiting three error values and the new error set will be hardcoded for
|
|
||||||
now, the the constructor for the internal error reporter just takes an object
|
|
||||||
ID for now.
|
|
||||||
|
|
||||||
### Device Handler Base
|
|
||||||
|
|
||||||
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
|
|
||||||
that DHB users adapt their polling sequence tables to perform this step. This steps allows for
|
|
||||||
a clear distinction between operation and communication steps
|
|
||||||
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
|
|
||||||
- getTransitionDelayMs is now an abstract method
|
|
||||||
|
|
||||||
### DeviceHandlerIF
|
|
||||||
|
|
||||||
- Typo for UNKNOWN_DEVICE_REPLY
|
|
||||||
|
|
||||||
### Events
|
|
||||||
|
|
||||||
- makeEvent function: Now takes three input parameters instead of two and
|
|
||||||
allows setting a unique ID. Event.cpp source file removed, functions now
|
|
||||||
defined in header directly. Namespaces renamed. Functions declared `constexpr`
|
|
||||||
now
|
|
||||||
|
|
||||||
### Commanding Service Base
|
|
||||||
|
|
||||||
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
|
|
||||||
CSB instance. This variable has to be set in the FSFWConfig.h file
|
|
||||||
|
|
||||||
### Service Interface
|
|
||||||
|
|
||||||
- Proper printf support contained in ServiceInterfacePrinter.h
|
|
||||||
- CPP ostream support now optional (can reduce executable size by 150 - 250 kB)
|
|
||||||
- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration.
|
|
||||||
Users can just use #include <fsfw/serviceinterface/ServiceInterface.h>
|
|
||||||
- If CPP streams are excluded, sif:: calls won't work anymore and need to be replaced by their printf counterparts.
|
|
||||||
For the fsfw, this can be done by checking the processor define FSFW_CPP_OSTREAM_ENABLED from FSFWConfig.h.
|
|
||||||
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
|
|
||||||
If this is not the case, everything should work as usual.
|
|
||||||
|
|
||||||
### ActionHelper and ActionMessage
|
|
||||||
|
|
||||||
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
|
|
||||||
information whether to report a success or failure message instead of deriving it implicitely
|
|
||||||
from returnvalue
|
|
||||||
|
|
||||||
### PUS Parameter Service 20
|
|
||||||
|
|
||||||
Added PUS parameter service 20 (only custom subservices available).
|
|
435
CHANGELOG.md
Normal file
435
CHANGELOG.md
Normal file
@ -0,0 +1,435 @@
|
|||||||
|
Change Log
|
||||||
|
=======
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
# [unreleased]
|
||||||
|
|
||||||
|
# [v5.0.0]
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||||
|
and mode
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||||
|
- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents
|
||||||
|
name clashes with Windows defines.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
|
- New CMake option `FSFW_HAL_LINUX_ADD_LIBGPIOD` to specifically exclude `gpiod` code.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
|
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||||
|
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue
|
||||||
|
creation call. It allows passing context information and an arbitrary user argument into
|
||||||
|
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||||
|
- Clock:
|
||||||
|
- `timeval` to `TimeOfDay_t`
|
||||||
|
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
||||||
|
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||||
|
- Better check for leap seconds
|
||||||
|
- Added Unittests for Clock (only getter)
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
||||||
|
datapools have been implemented.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/557
|
||||||
|
|
||||||
|
## Additions
|
||||||
|
|
||||||
|
- 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
|
||||||
|
- Added ETL dependency and improved library dependency management
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Small bugfix in STM32 HAL for SPI
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
||||||
|
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||||
|
configuration fails, the function will exit prematurely with a dedicated error code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/602
|
||||||
|
|
||||||
|
# [v4.0.0]
|
||||||
|
|
||||||
|
## Additions
|
||||||
|
|
||||||
|
- CFDP Packet Stack and related tests added. It also refactors the existing TMTC infastructure to
|
||||||
|
allow sending of CFDP packets to the CCSDS handlers.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/528
|
||||||
|
- added virtual function to print datasets
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/544
|
||||||
|
- doSendRead Hook
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/545
|
||||||
|
- Dockumentation for DHB
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/551
|
||||||
|
|
||||||
|
### HAL additions
|
||||||
|
|
||||||
|
- Linux Command Executor, which can execute shell commands in blocking and non-blocking mode
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/536
|
||||||
|
- uio Mapper
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/543
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Applied the `clang-format` auto-formatter to all source code
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/534
|
||||||
|
- Updated Catch2 to v3.0.0-preview4
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/538
|
||||||
|
- Changed CI to use prebuilt docker image
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/549
|
||||||
|
|
||||||
|
## Bugfix
|
||||||
|
|
||||||
|
- CMake fixes in PR https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/533 , was problematic
|
||||||
|
if the uppermost user `CMakeLists.txt` did not have the include paths set up properly, which
|
||||||
|
could lead to compile errors that `#include "fsfw/FSFW.h"` was not found.
|
||||||
|
- Fix for build regression in Catch2 v3.0.0-preview4
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/548
|
||||||
|
- Fix in unittest which failed on CI
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/552
|
||||||
|
- Fix in helper script
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/553
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
- Aforementioned changes to existing TMTC stack
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
# [v3.0.1]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
* Version number was not updated for v3.0.0 #542
|
||||||
|
|
||||||
|
## Enhancement
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
# [v3.0.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
#### TCP Socket Changes
|
||||||
|
|
||||||
|
* Keep Open TCP Implementation #496
|
||||||
|
* The socket will now kept open after disconnect. This allows reconnecting.
|
||||||
|
* Only one connection is allowed
|
||||||
|
* No internal influence but clients need to change their Code.
|
||||||
|
|
||||||
|
### GPIO IF
|
||||||
|
|
||||||
|
* Add feature to open GPIO by line name #506
|
||||||
|
|
||||||
|
### Bitutil
|
||||||
|
|
||||||
|
* Unittests for Op Divider and Bitutility #510
|
||||||
|
|
||||||
|
### Filesystem IF changed
|
||||||
|
|
||||||
|
* Filesystem Base Interface: Use IF instead of void pointer #511
|
||||||
|
|
||||||
|
### STM32
|
||||||
|
|
||||||
|
* STM32 SPI Updates #518
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
* Small bugfix for LIS3 handler #504
|
||||||
|
* Spelling fixed for function names #509
|
||||||
|
* CMakeLists fixes #517
|
||||||
|
* Out of bound reads and writes in unittests #519
|
||||||
|
* Bug in TmPacketStoredPusC (#478)
|
||||||
|
* Windows ifdef fixed #529
|
||||||
|
|
||||||
|
## Enhancement
|
||||||
|
|
||||||
|
* FSFW.h.in more default values #491
|
||||||
|
* Minor updates for PUS services #498
|
||||||
|
* HasReturnvaluesIF naming for parameter #499
|
||||||
|
* Tests can now be built as part of FSFW and versioning moved to CMake #500
|
||||||
|
* Added integration test code #508
|
||||||
|
* More printouts for rejected TC packets #505
|
||||||
|
* Arrayprinter format improvements #514
|
||||||
|
* Adding code for CI with docker and jenkins #520
|
||||||
|
* Added new function in SerializeAdapter #513
|
||||||
|
* Enables simple deSerialize if you keep track of the buffer position yourself
|
||||||
|
* `` static ReturnValue_t deSerialize(T *object, const uint8_t* buffer,
|
||||||
|
size_t* deserSize, SerializeIF::Endianness streamEndianness) ``
|
||||||
|
* Unittest helper scripts has a new Parameter to open the coverage html in the webrowser #525
|
||||||
|
* ``'-o', '--open', Open coverage data in webbrowser``
|
||||||
|
* Documentation updated. Sphinx Documentation can now be build with python script #526
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
* Version number was not updated for v3.0.0 #542
|
||||||
|
|
||||||
|
|
||||||
|
All Pull Requests:
|
||||||
|
|
||||||
|
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/19
|
||||||
|
|
||||||
|
# [v2.0.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
|
||||||
|
### File Structure changed to fit more common structure
|
||||||
|
|
||||||
|
* See pull request (#445)
|
||||||
|
* HAL is now part of the main project
|
||||||
|
* **See Instructions below:**
|
||||||
|
|
||||||
|
#### Instruction how to update existing / user code
|
||||||
|
|
||||||
|
* Changes in `#include`:
|
||||||
|
* Rename `internalError` in includes to `internalerror`
|
||||||
|
* Rename `fsfw/hal` to `fsfw_hal`
|
||||||
|
* Rename `fsfw/tests` to `fsfw_tests`
|
||||||
|
* Rename `osal/FreeRTOS` to `osal/freertos`
|
||||||
|
|
||||||
|
* Changes in `CMakeLists.txt`:
|
||||||
|
* Rename `OS_FSFW` to `FSFW_OSAL`
|
||||||
|
|
||||||
|
* Changes in `DleEncoder.cpp`
|
||||||
|
* Create an instance of the `DleEncoder` first before calling the `encode` and `decode` functions
|
||||||
|
|
||||||
|
### Removed osal/linux/Timer (#486)
|
||||||
|
|
||||||
|
* Was redundant to timemanager/Countdown
|
||||||
|
|
||||||
|
#### Instruction how to update existing / user code
|
||||||
|
|
||||||
|
* Use timemanager/Countdown instead
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
### TM Stack
|
||||||
|
|
||||||
|
* Increased TM stack robustness by introducing `nullptr` checks and more printouts (#483)
|
||||||
|
|
||||||
|
#### Host OSAL / FreeRTOS
|
||||||
|
|
||||||
|
* QueueMapManager Bugfix (NO_QUEUE was used as MessageQueueId) (#444)
|
||||||
|
|
||||||
|
#### Events
|
||||||
|
|
||||||
|
* Event output is now consistent (#447)
|
||||||
|
|
||||||
|
#### DLE Encoder
|
||||||
|
|
||||||
|
* Fixed possible out of bounds access in DLE Encoder (#492)
|
||||||
|
|
||||||
|
## Enhancment
|
||||||
|
|
||||||
|
* HAL as major new feature, also includes three MEMS devicehandlers as part of #481
|
||||||
|
* Linux HAL updates (#456)
|
||||||
|
* FreeRTOS Header cleaning update and Cmake tweaks (#442)
|
||||||
|
* Printer updates (#453)
|
||||||
|
* New returnvalue for for empty PST (#485)
|
||||||
|
* TMTC Bridge: Increase limit of packets stored (#484)
|
||||||
|
|
||||||
|
## Known bugs
|
||||||
|
|
||||||
|
* Bug in TmPacketStoredPusC (#478)
|
||||||
|
|
||||||
|
|
||||||
|
All Pull Requests:
|
||||||
|
|
||||||
|
Milestone: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/milestone/5
|
||||||
|
|
||||||
|
# [v1.2.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
### FSFW Architecture
|
||||||
|
|
||||||
|
- New src folder which contains all source files except the HAL, contributed code and test code
|
||||||
|
- External and internal API mostly stayed the same
|
||||||
|
- Folder names are now all smaller case: internalError was renamed to internalerror and
|
||||||
|
FreeRTOS was renamed to freertos
|
||||||
|
- Warning if optional headers are used but the modules was not added to the source files to compile
|
||||||
|
|
||||||
|
### HAL
|
||||||
|
|
||||||
|
- HAL added back into FSFW. It is tightly bound to the FSFW, and compiling it as a static library
|
||||||
|
made using it more complicated than necessary
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
### FreeRTOS QueueMapManager
|
||||||
|
|
||||||
|
- Fixed a bug which causes the first generated Queue ID to be invalid
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
|
||||||
|
### FSFW Architecture
|
||||||
|
|
||||||
|
- See API changes chapter. This change will keep the internal API consistent in the future
|
||||||
|
|
||||||
|
# [v1.1.0]
|
||||||
|
|
||||||
|
## API Changes
|
||||||
|
|
||||||
|
### PUS
|
||||||
|
|
||||||
|
- Added PUS C support
|
||||||
|
- SUBSYSTEM_IDs added for PUS Services
|
||||||
|
- Added new Parameter which must be defined in config: fsfwconfig::FSFW_MAX_TM_PACKET_SIZE
|
||||||
|
|
||||||
|
### ObjectManager
|
||||||
|
|
||||||
|
- ObjectManager is now a singelton
|
||||||
|
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
- Additional configuration option fsfwconfig::FSFW_MAX_TM_PACKET_SIZE which
|
||||||
|
need to be specified in FSFWConfig.h
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
- Changed Cmake FSFW_ADDITIONAL_INC_PATH to FSFW_ADDITIONAL_INC_PATHS
|
||||||
|
|
||||||
|
## Bugfixes
|
||||||
|
|
||||||
|
- timemanager/TimeStamperIF.h: Timestamp config was not used correctly, leading to different timestamp sizes than configured in fsfwconfig::FSFW_MISSION_TIMESTAMP_SIZE
|
||||||
|
- TCP server fixes
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
|
||||||
|
### FreeRTOS Queue Handles
|
||||||
|
|
||||||
|
- Fixed an internal issue how FreeRTOS MessageQueues were handled
|
||||||
|
|
||||||
|
### Linux OSAL
|
||||||
|
|
||||||
|
- Better printf error messages
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
- Check for C++11 as mininimum required Version
|
||||||
|
|
||||||
|
### Debug Output
|
||||||
|
|
||||||
|
- Changed Warning color to magenta, which is well readable on both dark and light mode IDEs
|
||||||
|
|
||||||
|
|
||||||
|
# Changes from ASTP 0.0.1 to 1.0.0
|
||||||
|
|
||||||
|
### Host OSAL
|
||||||
|
|
||||||
|
- Bugfix in MessageQueue, which caused the sender not to be set properly
|
||||||
|
|
||||||
|
### FreeRTOS OSAL
|
||||||
|
|
||||||
|
- vRequestContextSwitchFromISR is declared extern "C" so it can be defined in
|
||||||
|
a C file without issues
|
||||||
|
|
||||||
|
### PUS Services
|
||||||
|
|
||||||
|
- It is now possible to change the message queue depth for the telecommand verification service (PUS1)
|
||||||
|
- The same is possible for the event reporting service (PUS5)
|
||||||
|
- PUS Health Service added, which allows to command and retrieve health via PUS packets
|
||||||
|
|
||||||
|
|
||||||
|
### EnhancedControllerBase
|
||||||
|
|
||||||
|
- New base class for a controller which also implements HasActionsIF and HasLocalDataPoolIF
|
||||||
|
|
||||||
|
### Local Pool
|
||||||
|
|
||||||
|
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
|
||||||
|
bucket number of the pools per page and the number of pages are passed to the ctor instead of
|
||||||
|
two ctor arguments and a template parameter
|
||||||
|
|
||||||
|
### Parameter Service
|
||||||
|
|
||||||
|
- The API of the parameter service has been changed to prevent inconsistencies
|
||||||
|
between documentation and actual code and to clarify usage.
|
||||||
|
- The parameter ID now consists of:
|
||||||
|
1. Domain ID (1 byte)
|
||||||
|
2. Unique Identifier (1 byte)
|
||||||
|
3. Linear Index (2 bytes)
|
||||||
|
The linear index can be used for arrays as well as matrices.
|
||||||
|
The parameter load command now explicitely expects the ECSS PTC and PFC
|
||||||
|
information as well as the rows and column number. Rows and column will
|
||||||
|
default to one, which is equivalent to one scalar parameter (the most
|
||||||
|
important use-case)
|
||||||
|
|
||||||
|
### File System Interface
|
||||||
|
|
||||||
|
- A new interfaces specifies the functions for a software object which exposes the file system of
|
||||||
|
a given hardware to use message based file handling (e.g. PUS commanding)
|
||||||
|
|
||||||
|
### Internal Error Reporter
|
||||||
|
|
||||||
|
- The new internal error reporter uses the local data pools. The pool IDs for
|
||||||
|
the exisiting three error values and the new error set will be hardcoded for
|
||||||
|
now, the the constructor for the internal error reporter just takes an object
|
||||||
|
ID for now.
|
||||||
|
|
||||||
|
### Device Handler Base
|
||||||
|
|
||||||
|
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
|
||||||
|
that DHB users adapt their polling sequence tables to perform this step. This steps allows for
|
||||||
|
a clear distinction between operation and communication steps
|
||||||
|
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
|
||||||
|
- getTransitionDelayMs is now an abstract method
|
||||||
|
|
||||||
|
### DeviceHandlerIF
|
||||||
|
|
||||||
|
- Typo for UNKNOWN_DEVICE_REPLY
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
- makeEvent function: Now takes three input parameters instead of two and
|
||||||
|
allows setting a unique ID. Event.cpp source file removed, functions now
|
||||||
|
defined in header directly. Namespaces renamed. Functions declared `constexpr`
|
||||||
|
now
|
||||||
|
|
||||||
|
### Commanding Service Base
|
||||||
|
|
||||||
|
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
|
||||||
|
CSB instance. This variable has to be set in the FSFWConfig.h file
|
||||||
|
|
||||||
|
### Service Interface
|
||||||
|
|
||||||
|
- Proper printf support contained in ServiceInterfacePrinter.h
|
||||||
|
- CPP ostream support now optional (can reduce executable size by 150 - 250 kB)
|
||||||
|
- Amalagated header which determines automatically which service interface to use depending on FSFWConfig.h configuration.
|
||||||
|
Users can just use #include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
- If CPP streams are excluded, sif:: calls won't work anymore and need to be replaced by their printf counterparts.
|
||||||
|
For the fsfw, this can be done by checking the processor define FSFW_CPP_OSTREAM_ENABLED from FSFWConfig.h.
|
||||||
|
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
|
||||||
|
If this is not the case, everything should work as usual.
|
||||||
|
|
||||||
|
### ActionHelper and ActionMessage
|
||||||
|
|
||||||
|
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
|
||||||
|
information whether to report a success or failure message instead of deriving it implicitely
|
||||||
|
from returnvalue
|
||||||
|
|
||||||
|
### PUS Parameter Service 20
|
||||||
|
|
||||||
|
Added PUS parameter service 20 (only custom subservices available).
|
@ -1,12 +1,29 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(FSFW_VERSION 3)
|
set(FSFW_VERSION 4)
|
||||||
set(FSFW_SUBVERSION 0)
|
set(FSFW_SUBVERSION 0)
|
||||||
set(FSFW_REVISION 1)
|
set(FSFW_REVISION 0)
|
||||||
|
|
||||||
# Add the cmake folder so the FindSphinx module is found
|
# Add the cmake folder so the FindSphinx module is found
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
|
||||||
|
"ETL library major version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING
|
||||||
|
"ETL library exact version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
|
set(FSFW_CATCH2_LIB_MAJOR_VERSION 3 CACHE STRING
|
||||||
|
"Catch2 library major version requirement"
|
||||||
|
)
|
||||||
|
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
|
||||||
|
"Catch2 library exact version requirement"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
|
|
||||||
option(FSFW_GENERATE_SECTIONS
|
option(FSFW_GENERATE_SECTIONS
|
||||||
"Generate function and data sections. Required to remove unused code" ON
|
"Generate function and data sections. Required to remove unused code" ON
|
||||||
)
|
)
|
||||||
@ -48,19 +65,21 @@ add_library(${LIB_FSFW_NAME})
|
|||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_UNITTESTS)
|
||||||
message(STATUS "Building the FSFW unittests in addition to the static library")
|
message(STATUS "Building the FSFW unittests in addition to the static library")
|
||||||
# Check whether the user has already installed Catch2 first
|
# Check whether the user has already installed Catch2 first
|
||||||
find_package(Catch2 3)
|
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
||||||
# Not installed, so use FetchContent to download and provide Catch2
|
# Not installed, so use FetchContent to download and provide Catch2
|
||||||
if(NOT Catch2_FOUND)
|
if(NOT Catch2_FOUND)
|
||||||
|
message(STATUS "Catch2 installation not found. Downloading Catch2 library with FetchContent")
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
Catch2
|
Catch2
|
||||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
GIT_TAG v3.0.0-preview4
|
GIT_TAG ${FSFW_CATCH2_LIB_VERSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_MakeAvailable(Catch2)
|
FetchContent_MakeAvailable(Catch2)
|
||||||
#fixes regression -preview4, to be confirmed in later releases
|
# fixes regression -preview4, to be confirmed in later releases
|
||||||
|
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -88,6 +107,28 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Finding and/or providing ETL library")
|
||||||
|
|
||||||
|
# Check whether the user has already installed ETL first
|
||||||
|
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(STATUS
|
||||||
|
"No ETL installation was found with find_package. Installing and providing "
|
||||||
|
"etl with FindPackage"
|
||||||
|
)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
${FSFW_ETL_LIB_NAME}
|
||||||
|
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||||
|
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(${FSFW_ETL_LIB_NAME})
|
||||||
|
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
set(FSFW_CORE_INC_PATH "inc")
|
set(FSFW_CORE_INC_PATH "inc")
|
||||||
|
|
||||||
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
|
||||||
@ -281,6 +322,24 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
-Wimplicit-fallthrough=1
|
-Wimplicit-fallthrough=1
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-psabi
|
-Wno-psabi
|
||||||
|
-Wduplicated-cond # check for duplicate conditions
|
||||||
|
-Wduplicated-branches # check for duplicate branches
|
||||||
|
-Wlogical-op # Search for bitwise operations instead of logical
|
||||||
|
-Wnull-dereference # Search for NULL dereference
|
||||||
|
-Wundef # Warn if undefind marcos are used
|
||||||
|
-Wformat=2 # Format string problem detection
|
||||||
|
-Wformat-overflow=2 # Formatting issues in printf
|
||||||
|
-Wformat-truncation=2 # Formatting issues in printf
|
||||||
|
-Wformat-security # Search for dangerous printf operations
|
||||||
|
-Wstrict-overflow=3 # Warn if integer overflows might happen
|
||||||
|
-Warray-bounds=2 # Some array bounds violations will be found
|
||||||
|
-Wshift-overflow=2 # Search for bit left shift overflows (<c++14)
|
||||||
|
-Wcast-qual # Warn if the constness is cast away
|
||||||
|
-Wstringop-overflow=4
|
||||||
|
# -Wstack-protector # Emits a few false positives for low level access
|
||||||
|
# -Wconversion # Creates many false positives
|
||||||
|
# -Warith-conversion # Use with Wconversion to find more implicit conversions
|
||||||
|
# -fanalyzer # Should be used to look through problems
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -331,6 +390,7 @@ target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
${FSFW_ETL_LINK_TARGET}
|
||||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
${FSFW_ADDITIONAL_LINK_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
83
README.md
83
README.md
@ -11,9 +11,15 @@ with Airbus Defence and Space GmbH.
|
|||||||
|
|
||||||
## Quick facts
|
## Quick facts
|
||||||
|
|
||||||
The framework is designed for systems, which communicate with external devices, perform control loops, receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore, a mode and health system provides control over the states of the software and the controlled devices. In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
The framework is designed for systems, which communicate with external devices, perform control loops,
|
||||||
|
receive telecommands and send telemetry, and need to maintain a high level of availability. Therefore,
|
||||||
|
a mode and health system provides control over the states of the software and the controlled devices.
|
||||||
|
In addition, a simple mechanism of event based fault detection, isolation and recovery is implemented as well.
|
||||||
|
|
||||||
The FSFW provides abstraction layers for operating systems to provide a uniform operating system abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is also very useful for developers to implement the same application logic on different operating systems with a uniform interface.
|
The FSFW provides abstraction layers for operating systems to provide a uniform operating system
|
||||||
|
abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
|
||||||
|
also very useful for developers to implement the same application logic on different operating
|
||||||
|
systems with a uniform interface.
|
||||||
|
|
||||||
Currently, the FSFW provides the following OSALs:
|
Currently, the FSFW provides the following OSALs:
|
||||||
|
|
||||||
@ -45,6 +51,28 @@ A template configuration folder was provided and can be copied into the project
|
|||||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||||
information about the possible options.
|
information about the possible options.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||||
|
installed and provided by the build system unless the correction version was installed.
|
||||||
|
The current recommended version can be found inside the fsfw `CMakeLists.txt` file or by using
|
||||||
|
`ccmake` and looking up the `FSFW_ETL_LIB_MAJOR_VERSION` variable.
|
||||||
|
|
||||||
|
You can install the ETL library like this. On Linux, it might be necessary to add `sudo` before
|
||||||
|
the install call:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
git clone https://github.com/ETLCPP/etl
|
||||||
|
cd etl
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --install .
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to install `20.27.2` or newer for the package version handling of
|
||||||
|
ETL to work.
|
||||||
|
|
||||||
## Adding the library
|
## Adding the library
|
||||||
|
|
||||||
The following steps show how to add and use FSFW components. It is still recommended to
|
The following steps show how to add and use FSFW components. It is still recommended to
|
||||||
@ -72,7 +100,7 @@ add and link against the FSFW library in general.
|
|||||||
4. Link against the FSFW library
|
4. Link against the FSFW library
|
||||||
|
|
||||||
```cmake
|
```cmake
|
||||||
target_link_libraries(<YourProjectName> PRIVATE fsfw)
|
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||||
```
|
```
|
||||||
|
|
||||||
5. It should now be possible use the FSFW as a static library from the user code.
|
5. It should now be possible use the FSFW as a static library from the user code.
|
||||||
@ -83,6 +111,19 @@ The FSFW also has unittests which use the [Catch2 library](https://github.com/ca
|
|||||||
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
|
These are built by setting the CMake option `FSFW_BUILD_UNITTESTS` to `ON` or `TRUE`
|
||||||
from your project `CMakeLists.txt` file or from the command line.
|
from your project `CMakeLists.txt` file or from the command line.
|
||||||
|
|
||||||
|
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||||
|
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||||
|
can be found inside the fsfw `CMakeLists.txt` file or by using `ccmake` and looking up
|
||||||
|
the `FSFW_CATCH2_LIB_VERSION` variable.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/catchorg/Catch2.git
|
||||||
|
cd Catch2
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
sudo cmake --build build/ --target install
|
||||||
|
```
|
||||||
|
|
||||||
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
||||||
If the unittests are built, the library and the tests will be built with coverage information by
|
If the unittests are built, the library and the tests will be built with coverage information by
|
||||||
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
||||||
@ -107,6 +148,42 @@ cmake --build . -- fsfw-tests_coverage -j
|
|||||||
|
|
||||||
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
|
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
|
||||||
|
|
||||||
|
## Building the documentations
|
||||||
|
|
||||||
|
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
|
||||||
|
instructions provided in [this blogpost](https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/). If you
|
||||||
|
want to do this locally, set up the prerequisites first. This requires a ``python3``
|
||||||
|
installation as well. Example here is for Ubuntu.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt-get install doxygen graphviz
|
||||||
|
```
|
||||||
|
|
||||||
|
And the following Python packages
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 -m pip install sphinx breathe
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set up a documentation build system using the following commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir build-docs && cd build-docs
|
||||||
|
cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can generate the documentation using
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake --build . -j
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the generated documentation inside the `docs/sphinx` folder inside the build
|
||||||
|
folder. Simply open the `index.html` in the webbrowser of your choice.
|
||||||
|
|
||||||
|
The `helper.py` script located in the script` folder can also be used to create, build
|
||||||
|
and open the documentation conveniently. Try `helper.py -h for more information.
|
||||||
|
|
||||||
## Formatting the sources
|
## Formatting the sources
|
||||||
|
|
||||||
The formatting is done by the `clang-format` tool. The configuration is contained within the
|
The formatting is done by the `clang-format` tool. The configuration is contained within the
|
||||||
|
@ -6,3 +6,9 @@ RUN apt-get --yes upgrade
|
|||||||
#tzdata is a dependency, won't install otherwise
|
#tzdata is a dependency, won't install otherwise
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
|
||||||
|
|
||||||
|
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||||
|
cd Catch2 && \
|
||||||
|
git checkout v3.0.0-preview5 && \
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||||
|
cmake --build build/ --target install
|
||||||
|
6
automation/Jenkinsfile
vendored
6
automation/Jenkinsfile
vendored
@ -3,7 +3,7 @@ pipeline {
|
|||||||
BUILDDIR = 'build-tests'
|
BUILDDIR = 'build-tests'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker { image 'fsfw-ci:d1'}
|
docker { image 'fsfw-ci:d2'}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('Clean') {
|
stage('Clean') {
|
||||||
@ -21,14 +21,14 @@ pipeline {
|
|||||||
stage('Build') {
|
stage('Build') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR) {
|
||||||
sh 'cmake --build . -j'
|
sh 'cmake --build . -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Unittests') {
|
stage('Unittests') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR) {
|
||||||
sh 'cmake --build . -- fsfw-tests_coverage -j'
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,110 @@
|
|||||||
|
.. _dhb-prim-doc:
|
||||||
|
|
||||||
Device Handlers
|
Device Handlers
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
Device handler components represent, control and monitor equipment, for example sensors or actuators
|
||||||
|
of a spacecraft or the payload.
|
||||||
|
|
||||||
|
Most device handlers have the same common functionality or
|
||||||
|
requirements, which are fulfilled by implementing certain interfaces:
|
||||||
|
|
||||||
|
- The handler/device needs to be commandable: :cpp:class:`HasActionsIF`
|
||||||
|
- The handler needs to communicate with the physical device via a dedicated
|
||||||
|
communication bus, for example SpaceWire, UART or SPI: :cpp:class:`DeviceCommunicationIF`
|
||||||
|
- The handler has housekeeping data which has to be exposed to the operator and/or other software
|
||||||
|
components: :cpp:class:`HasLocalDataPoolIF`
|
||||||
|
- The handler has configurable parameters: :cpp:class:`ReceivesParameterMessagesIF` which
|
||||||
|
also implements :cpp:class:`HasParametersIF`
|
||||||
|
- The handler has health states, for example to indicate a broken device:
|
||||||
|
:cpp:class:`HasHealthIF`
|
||||||
|
- The handler has modes. For example there are the core modes `MODE_ON`, `MODE_OFF`
|
||||||
|
and `MODE_NORMAL` provided by the FSFW. `MODE_ON` means that a device is physically powered
|
||||||
|
but that it is not periodically polling data from the
|
||||||
|
physical device, `MODE_NORMAL` means that it is able to do that: :cpp:class:`HasModesIF`
|
||||||
|
|
||||||
|
The device handler base therefore provides abstractions for a lot of common
|
||||||
|
functionality, which can potentially avoid high amounts or logic and code duplication.
|
||||||
|
|
||||||
|
Template Device Handler Base File
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
This is an example template device handler header file with all necessary
|
||||||
|
functions implemented:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#ifndef __TESTDEVICEHANDLER_H_
|
||||||
|
#define __TESTDEVICEHANDLER_H_
|
||||||
|
|
||||||
|
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
|
||||||
|
|
||||||
|
class TestDeviceHandler: DeviceHandlerBase {
|
||||||
|
public:
|
||||||
|
TestDeviceHandler(object_id_t objectId, object_id_t comIF, CookieIF* cookie);
|
||||||
|
private:
|
||||||
|
void doStartUp() override;
|
||||||
|
void doShutDown() override;
|
||||||
|
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override;
|
||||||
|
ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t* id) override;
|
||||||
|
void fillCommandAndReplyMap() override;
|
||||||
|
ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData,
|
||||||
|
size_t commandDataLen) override;
|
||||||
|
ReturnValue_t scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId,
|
||||||
|
size_t* foundLen) override;
|
||||||
|
ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) override;
|
||||||
|
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
|
||||||
|
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
|
LocalDataPoolManager& poolManager) override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __TESTDEVICEHANDLER_H_ */
|
||||||
|
|
||||||
|
and the respective source file with sensible default return values:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include "TestDeviceHandler.h"
|
||||||
|
|
||||||
|
TestDeviceHandler::TestDeviceHandler(object_id_t objectId, object_id_t comIF, CookieIF* cookie)
|
||||||
|
: DeviceHandlerBase(objectId, comIF, cookie) {}
|
||||||
|
|
||||||
|
void TestDeviceHandler::doStartUp() {}
|
||||||
|
|
||||||
|
void TestDeviceHandler::doShutDown() {}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestDeviceHandler::fillCommandAndReplyMap() {}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand,
|
||||||
|
const uint8_t* commandData,
|
||||||
|
size_t commandDataLen) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize,
|
||||||
|
DeviceCommandId_t* foundId, size_t* foundLen) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::interpretDeviceReply(DeviceCommandId_t id,
|
||||||
|
const uint8_t* packet) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TestDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) {
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TestDeviceHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
|
LocalDataPoolManager& poolManager) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,29 @@ A template configuration folder was provided and can be copied into the project
|
|||||||
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
a starting point. The [configuration section](docs/README-config.md#top) provides more specific
|
||||||
information about the possible options.
|
information about the possible options.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The Embedded Template Library (etl) is a dependency of the FSFW which is automatically
|
||||||
|
installed and provided by the build system unless the correction version was installed.
|
||||||
|
The current recommended version can be found inside the fsfw ``CMakeLists.txt`` file or by using
|
||||||
|
``ccmake`` and looking up the ``FSFW_ETL_LIB_MAJOR_VERSION`` variable.
|
||||||
|
|
||||||
|
You can install the ETL library like this. On Linux, it might be necessary to add ``sudo`` before
|
||||||
|
the install call:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
git clone https://github.com/ETLCPP/etl
|
||||||
|
cd etl
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --install .
|
||||||
|
|
||||||
|
It is recommended to install ``20.27.2`` or newer for the package version handling of
|
||||||
|
ETL to work.
|
||||||
|
|
||||||
Adding the library
|
Adding the library
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
@ -60,6 +83,20 @@ The FSFW also has unittests which use the `Catch2 library`_.
|
|||||||
These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
|
These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
|
||||||
from your project `CMakeLists.txt` file or from the command line.
|
from your project `CMakeLists.txt` file or from the command line.
|
||||||
|
|
||||||
|
You can install the Catch2 library, which prevents the build system to avoid re-downloading
|
||||||
|
the dependency if the unit tests are completely rebuilt. The current recommended version
|
||||||
|
can be found inside the fsfw ``CMakeLists.txt`` file or by using ``ccmake`` and looking up
|
||||||
|
the ``FSFW_CATCH2_LIB_VERSION`` variable.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
git clone https://github.com/catchorg/Catch2.git
|
||||||
|
cd Catch2
|
||||||
|
git checkout <currentRecommendedVersion>
|
||||||
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF
|
||||||
|
sudo cmake --build build/ --target install
|
||||||
|
|
||||||
|
|
||||||
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
The fsfw-tests binary will be built as part of the static library and dropped alongside it.
|
||||||
If the unittests are built, the library and the tests will be built with coverage information by
|
If the unittests are built, the library and the tests will be built with coverage information by
|
||||||
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
|
||||||
@ -90,8 +127,21 @@ Building the documentation
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
|
The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
|
||||||
instructions provided in `this blogpost <https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/>`_. You can set up a
|
instructions provided in `this blogpost <https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/>`_. If you
|
||||||
documentation build system using the following commands
|
want to do this locally, set up the prerequisites first. This requires a ``python3``
|
||||||
|
installation as well. Example here is for Ubuntu.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
sudo apt-get install doxygen graphviz
|
||||||
|
|
||||||
|
And the following Python packages
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
python3 -m pip install sphinx breathe
|
||||||
|
|
||||||
|
You can set up a documentation build system using the following commands
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
@ -110,6 +160,14 @@ folder. Simply open the ``index.html`` in the webbrowser of your choice.
|
|||||||
The ``helper.py`` script located in the ``script`` folder can also be used to create, build
|
The ``helper.py`` script located in the ``script`` folder can also be used to create, build
|
||||||
and open the documentation conveniently. Try ``helper.py -h`` for more information.
|
and open the documentation conveniently. Try ``helper.py -h`` for more information.
|
||||||
|
|
||||||
|
Formatting the source
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The formatting is done by the ``clang-format`` tool. The configuration is contained within the
|
||||||
|
``.clang-format`` file in the repository root. As long as ``clang-format`` is installed, you
|
||||||
|
can run the ``apply-clang-format.sh`` helper script to format all source files consistently.
|
||||||
|
|
||||||
|
|
||||||
.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted
|
.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted
|
||||||
.. _`Catch2 library`: https://github.com/catchorg/Catch2
|
.. _`Catch2 library`: https://github.com/catchorg/Catch2
|
||||||
.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master
|
.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master
|
||||||
|
@ -118,7 +118,7 @@ The DH has mechanisms to monitor the communication with the physical device whic
|
|||||||
for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``.
|
for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``.
|
||||||
A standard FDIR component for the DH will be created automatically but can
|
A standard FDIR component for the DH will be created automatically but can
|
||||||
be overwritten by the user. More information on DeviceHandlers can be found in the
|
be overwritten by the user. More information on DeviceHandlers can be found in the
|
||||||
related [documentation section](doc/README-devicehandlers.md#top).
|
related :ref:`documentation section <dhb-prim-doc>`.
|
||||||
|
|
||||||
Modes and Health
|
Modes and Health
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -9,6 +9,7 @@ option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Requires gpiod libr
|
|||||||
# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
|
# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
|
||||||
# but CMake is able to determine whether this library is installed with find_library.
|
# but CMake is able to determine whether this library is installed with find_library.
|
||||||
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
|
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
|
||||||
|
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Target implements libgpiod" ON)
|
||||||
|
|
||||||
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
|
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
|
||||||
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
|
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
|
||||||
|
@ -9,11 +9,11 @@ using gpioId_t = uint16_t;
|
|||||||
|
|
||||||
namespace gpio {
|
namespace gpio {
|
||||||
|
|
||||||
enum Levels : uint8_t { LOW = 0, HIGH = 1, NONE = 99 };
|
enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
|
||||||
|
|
||||||
enum Direction : uint8_t { IN = 0, OUT = 1 };
|
enum class Direction : int { IN = 0, OUT = 1 };
|
||||||
|
|
||||||
enum GpioOperation { READ, WRITE };
|
enum class GpioOperation { READ, WRITE };
|
||||||
|
|
||||||
enum class GpioTypes {
|
enum class GpioTypes {
|
||||||
NONE,
|
NONE,
|
||||||
@ -80,7 +80,7 @@ class GpiodRegularByChip : public GpiodRegularBase {
|
|||||||
public:
|
public:
|
||||||
GpiodRegularByChip()
|
GpiodRegularByChip()
|
||||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(), gpio::Direction::IN,
|
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, std::string(), gpio::Direction::IN,
|
||||||
gpio::LOW, 0) {}
|
gpio::Levels::LOW, 0) {}
|
||||||
|
|
||||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
|
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_,
|
||||||
gpio::Direction direction_, gpio::Levels initValue_)
|
gpio::Direction direction_, gpio::Levels initValue_)
|
||||||
@ -90,7 +90,7 @@ class GpiodRegularByChip : public GpiodRegularBase {
|
|||||||
|
|
||||||
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_)
|
GpiodRegularByChip(std::string chipname_, int lineNum_, std::string consumer_)
|
||||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::IN,
|
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_CHIP, consumer_, gpio::Direction::IN,
|
||||||
gpio::LOW, lineNum_),
|
gpio::Levels::LOW, lineNum_),
|
||||||
chipname(chipname_) {}
|
chipname(chipname_) {}
|
||||||
|
|
||||||
std::string chipname;
|
std::string chipname;
|
||||||
@ -106,7 +106,7 @@ class GpiodRegularByLabel : public GpiodRegularBase {
|
|||||||
|
|
||||||
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_)
|
GpiodRegularByLabel(std::string label_, int lineNum_, std::string consumer_)
|
||||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::IN,
|
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LABEL, consumer_, gpio::Direction::IN,
|
||||||
gpio::LOW, lineNum_),
|
gpio::Levels::LOW, lineNum_),
|
||||||
label(label_) {}
|
label(label_) {}
|
||||||
|
|
||||||
std::string label;
|
std::string label;
|
||||||
@ -127,7 +127,7 @@ class GpiodRegularByLineName : public GpiodRegularBase {
|
|||||||
|
|
||||||
GpiodRegularByLineName(std::string lineName_, std::string consumer_)
|
GpiodRegularByLineName(std::string lineName_, std::string consumer_)
|
||||||
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN,
|
: GpiodRegularBase(gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME, consumer_, gpio::Direction::IN,
|
||||||
gpio::LOW),
|
gpio::Levels::LOW),
|
||||||
lineName(lineName_) {}
|
lineName(lineName_) {}
|
||||||
|
|
||||||
std::string lineName;
|
std::string lineName;
|
||||||
|
@ -8,11 +8,7 @@ GyroHandlerL3GD20H::GyroHandlerL3GD20H(object_id_t objectId, object_id_t deviceC
|
|||||||
CookieIF *comCookie, uint32_t transitionDelayMs)
|
CookieIF *comCookie, uint32_t transitionDelayMs)
|
||||||
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
||||||
transitionDelayMs(transitionDelayMs),
|
transitionDelayMs(transitionDelayMs),
|
||||||
dataset(this) {
|
dataset(this) {}
|
||||||
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
|
|
||||||
debugDivider = new PeriodicOperationDivider(3);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
GyroHandlerL3GD20H::~GyroHandlerL3GD20H() {}
|
GyroHandlerL3GD20H::~GyroHandlerL3GD20H() {}
|
||||||
|
|
||||||
@ -193,8 +189,8 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
|
|||||||
|
|
||||||
int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX];
|
int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX];
|
||||||
float temperature = 25.0 + temperaturOffset;
|
float temperature = 25.0 + temperaturOffset;
|
||||||
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
|
if (periodicPrintout) {
|
||||||
if (debugDivider->checkAndIncrement()) {
|
if (debugDivider.checkAndIncrement()) {
|
||||||
/* Set terminal to utf-8 if there is an issue with micro printout. */
|
/* Set terminal to utf-8 if there is an issue with micro printout. */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::info << "GyroHandlerL3GD20H: Angular velocities (deg/s):" << std::endl;
|
sif::info << "GyroHandlerL3GD20H: Angular velocities (deg/s):" << std::endl;
|
||||||
@ -208,7 +204,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id,
|
|||||||
sif::printInfo("Z: %f\n", angVelocZ);
|
sif::printInfo("Z: %f\n", angVelocZ);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
PoolReadGuard readSet(&dataset);
|
PoolReadGuard readSet(&dataset);
|
||||||
if (readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
if (readSet.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||||
@ -272,3 +268,8 @@ void GyroHandlerL3GD20H::setAbsoluteLimits(float limitX, float limitY, float lim
|
|||||||
this->absLimitY = limitY;
|
this->absLimitY = limitY;
|
||||||
this->absLimitZ = limitZ;
|
this->absLimitZ = limitZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GyroHandlerL3GD20H::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||||
|
periodicPrintout = enable;
|
||||||
|
debugDivider.setDivider(divider);
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
|
#include <fsfw/globalfunctions/PeriodicOperationDivider.h>
|
||||||
|
|
||||||
#include "devicedefinitions/GyroL3GD20Definitions.h"
|
#include "devicedefinitions/GyroL3GD20Definitions.h"
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Device Handler for the L3GD20H gyroscope sensor
|
* @brief Device Handler for the L3GD20H gyroscope sensor
|
||||||
@ -22,6 +21,8 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
|
|||||||
uint32_t transitionDelayMs);
|
uint32_t transitionDelayMs);
|
||||||
virtual ~GyroHandlerL3GD20H();
|
virtual ~GyroHandlerL3GD20H();
|
||||||
|
|
||||||
|
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the absolute limit for the values on the axis in degrees per second.
|
* Set the absolute limit for the values on the axis in degrees per second.
|
||||||
* The dataset values will be marked as invalid if that limit is exceeded
|
* The dataset values will be marked as invalid if that limit is exceeded
|
||||||
@ -80,9 +81,8 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase {
|
|||||||
// Set default value
|
// Set default value
|
||||||
float sensitivity = L3GD20H::SENSITIVITY_00;
|
float sensitivity = L3GD20H::SENSITIVITY_00;
|
||||||
|
|
||||||
#if FSFW_HAL_L3GD20_GYRO_DEBUG == 1
|
bool periodicPrintout = false;
|
||||||
PeriodicOperationDivider *debugDivider = nullptr;
|
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_DEVICES_GYROL3GD20HANDLER_H_ */
|
#endif /* MISSION_DEVICES_GYROL3GD20HANDLER_H_ */
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
#include "MgmLIS3MDLHandler.h"
|
#include "MgmLIS3MDLHandler.h"
|
||||||
|
|
||||||
#include "fsfw/datapool/PoolReadGuard.h"
|
|
||||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
|
||||||
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "fsfw/datapool/PoolReadGuard.h"
|
||||||
|
|
||||||
MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication,
|
MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCommunication,
|
||||||
CookieIF *comCookie, uint32_t transitionDelay)
|
CookieIF *comCookie, uint32_t transitionDelay)
|
||||||
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
||||||
dataset(this),
|
dataset(this),
|
||||||
transitionDelay(transitionDelay) {
|
transitionDelay(transitionDelay) {
|
||||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
|
||||||
debugDivider = new PeriodicOperationDivider(3);
|
|
||||||
#endif
|
|
||||||
// Set to default values right away
|
// Set to default values right away
|
||||||
registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT;
|
registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT;
|
||||||
registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT;
|
registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT;
|
||||||
@ -264,7 +258,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
|||||||
int16_t mgmMeasurementRawZ =
|
int16_t mgmMeasurementRawZ =
|
||||||
packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX];
|
packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX];
|
||||||
|
|
||||||
/* Target value in microtesla */
|
// Target value in microtesla
|
||||||
float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor *
|
float mgmX = static_cast<float>(mgmMeasurementRawX) * sensitivityFactor *
|
||||||
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
||||||
float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor *
|
float mgmY = static_cast<float>(mgmMeasurementRawY) * sensitivityFactor *
|
||||||
@ -272,8 +266,8 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
|||||||
float mgmZ = static_cast<float>(mgmMeasurementRawZ) * sensitivityFactor *
|
float mgmZ = static_cast<float>(mgmMeasurementRawZ) * sensitivityFactor *
|
||||||
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR;
|
||||||
|
|
||||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
if (periodicPrintout) {
|
||||||
if (debugDivider->checkAndIncrement()) {
|
if (debugDivider.checkAndIncrement()) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::info << "MGMHandlerLIS3: Magnetic field strength in"
|
sif::info << "MGMHandlerLIS3: Magnetic field strength in"
|
||||||
" microtesla:"
|
" microtesla:"
|
||||||
@ -288,7 +282,8 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
|||||||
sif::printInfo("Z: %f uT\n", mgmZ);
|
sif::printInfo("Z: %f uT\n", mgmZ);
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 0 */
|
||||||
}
|
}
|
||||||
#endif /* OBSW_VERBOSE_LEVEL >= 1 */
|
}
|
||||||
|
|
||||||
PoolReadGuard readHelper(&dataset);
|
PoolReadGuard readHelper(&dataset);
|
||||||
if (readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
if (readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
|
||||||
if (std::abs(mgmX) < absLimitX) {
|
if (std::abs(mgmX) < absLimitX) {
|
||||||
@ -318,15 +313,16 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons
|
|||||||
case MGMLIS3MDL::READ_TEMPERATURE: {
|
case MGMLIS3MDL::READ_TEMPERATURE: {
|
||||||
int16_t tempValueRaw = packet[2] << 8 | packet[1];
|
int16_t tempValueRaw = packet[2] << 8 | packet[1];
|
||||||
float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0);
|
float tempValue = 25.0 + ((static_cast<float>(tempValueRaw)) / 8.0);
|
||||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
if (periodicPrintout) {
|
||||||
if (debugDivider->check()) {
|
if (debugDivider.check()) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << std::endl;
|
sif::info << "MGMHandlerLIS3: Temperature: " << tempValue << " C" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n");
|
sif::printInfo("MGMHandlerLIS3: Temperature: %f C\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
ReturnValue_t result = dataset.read();
|
ReturnValue_t result = dataset.read();
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
if (result == HasReturnvaluesIF::RETURN_OK) {
|
||||||
dataset.temperature = tempValue;
|
dataset.temperature = tempValue;
|
||||||
@ -462,7 +458,9 @@ ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() {
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {}
|
void MgmLIS3MDLHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
|
||||||
|
DeviceHandlerBase::doTransition(modeFrom, subModeFrom);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { return transitionDelay; }
|
uint32_t MgmLIS3MDLHandler::getTransitionDelayMs(Mode_t from, Mode_t to) { return transitionDelay; }
|
||||||
|
|
||||||
@ -482,3 +480,8 @@ void MgmLIS3MDLHandler::setAbsoluteLimits(float xLimit, float yLimit, float zLim
|
|||||||
this->absLimitY = yLimit;
|
this->absLimitY = yLimit;
|
||||||
this->absLimitZ = zLimit;
|
this->absLimitZ = zLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MgmLIS3MDLHandler::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||||
|
periodicPrintout = enable;
|
||||||
|
debugDivider.setDivider(divider);
|
||||||
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "devicedefinitions/MgmLIS3HandlerDefs.h"
|
#include "devicedefinitions/MgmLIS3HandlerDefs.h"
|
||||||
#include "events/subsystemIdRanges.h"
|
#include "events/subsystemIdRanges.h"
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||||
|
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
||||||
|
|
||||||
class PeriodicOperationDivider;
|
class PeriodicOperationDivider;
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
|
|||||||
uint32_t transitionDelay);
|
uint32_t transitionDelay);
|
||||||
virtual ~MgmLIS3MDLHandler();
|
virtual ~MgmLIS3MDLHandler();
|
||||||
|
|
||||||
|
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||||
/**
|
/**
|
||||||
* Set the absolute limit for the values on the axis in microtesla. The dataset values will
|
* Set the absolute limit for the values on the axis in microtesla. The dataset values will
|
||||||
* be marked as invalid if that limit is exceeded
|
* be marked as invalid if that limit is exceeded
|
||||||
@ -167,9 +168,8 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t prepareCtrlRegisterWrite();
|
ReturnValue_t prepareCtrlRegisterWrite();
|
||||||
|
|
||||||
#if FSFW_HAL_LIS3MDL_MGM_DEBUG == 1
|
bool periodicPrintout = false;
|
||||||
PeriodicOperationDivider *debugDivider;
|
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */
|
#endif /* MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ */
|
||||||
|
@ -10,11 +10,7 @@ MgmRM3100Handler::MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommu
|
|||||||
CookieIF *comCookie, uint32_t transitionDelay)
|
CookieIF *comCookie, uint32_t transitionDelay)
|
||||||
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
: DeviceHandlerBase(objectId, deviceCommunication, comCookie),
|
||||||
primaryDataset(this),
|
primaryDataset(this),
|
||||||
transitionDelay(transitionDelay) {
|
transitionDelay(transitionDelay) {}
|
||||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
|
||||||
debugDivider = new PeriodicOperationDivider(3);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
MgmRM3100Handler::~MgmRM3100Handler() {}
|
MgmRM3100Handler::~MgmRM3100Handler() {}
|
||||||
|
|
||||||
@ -337,8 +333,8 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
|||||||
float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
|
float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
|
||||||
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
|
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
|
||||||
|
|
||||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
if (periodicPrintout) {
|
||||||
if (debugDivider->checkAndIncrement()) {
|
if (debugDivider.checkAndIncrement()) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::info << "MgmRM3100Handler: Magnetic field strength in"
|
sif::info << "MgmRM3100Handler: Magnetic field strength in"
|
||||||
" microtesla:"
|
" microtesla:"
|
||||||
@ -353,7 +349,7 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
|||||||
sif::printInfo("Z: %f uT\n", fieldStrengthZ);
|
sif::printInfo("Z: %f uT\n", fieldStrengthZ);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
|
|
||||||
// TODO: Sanity check on values?
|
// TODO: Sanity check on values?
|
||||||
PoolReadGuard readGuard(&primaryDataset);
|
PoolReadGuard readGuard(&primaryDataset);
|
||||||
@ -365,3 +361,8 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
|||||||
}
|
}
|
||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MgmRM3100Handler::enablePeriodicPrintouts(bool enable, uint8_t divider) {
|
||||||
|
periodicPrintout = enable;
|
||||||
|
debugDivider.setDivider(divider);
|
||||||
|
}
|
||||||
|
@ -2,12 +2,8 @@
|
|||||||
#define MISSION_DEVICES_MGMRM3100HANDLER_H_
|
#define MISSION_DEVICES_MGMRM3100HANDLER_H_
|
||||||
|
|
||||||
#include "devicedefinitions/MgmRM3100HandlerDefs.h"
|
#include "devicedefinitions/MgmRM3100HandlerDefs.h"
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||||
|
|
||||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
|
||||||
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Device Handler for the RM3100 geomagnetic magnetometer sensor
|
* @brief Device Handler for the RM3100 geomagnetic magnetometer sensor
|
||||||
@ -33,6 +29,7 @@ class MgmRM3100Handler : public DeviceHandlerBase {
|
|||||||
uint32_t transitionDelay);
|
uint32_t transitionDelay);
|
||||||
virtual ~MgmRM3100Handler();
|
virtual ~MgmRM3100Handler();
|
||||||
|
|
||||||
|
void enablePeriodicPrintouts(bool enable, uint8_t divider);
|
||||||
/**
|
/**
|
||||||
* Configure device handler to go to normal mode after startup immediately
|
* Configure device handler to go to normal mode after startup immediately
|
||||||
* @param enable
|
* @param enable
|
||||||
@ -98,9 +95,9 @@ class MgmRM3100Handler : public DeviceHandlerBase {
|
|||||||
size_t commandDataLen);
|
size_t commandDataLen);
|
||||||
|
|
||||||
ReturnValue_t handleDataReadout(const uint8_t *packet);
|
ReturnValue_t handleDataReadout(const uint8_t *packet);
|
||||||
#if FSFW_HAL_RM3100_MGM_DEBUG == 1
|
|
||||||
PeriodicOperationDivider *debugDivider;
|
bool periodicPrintout = false;
|
||||||
#endif
|
PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */
|
#endif /* MISSION_DEVICEHANDLING_MGMRM3100HANDLER_H_ */
|
||||||
|
@ -9,8 +9,12 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
|||||||
)
|
)
|
||||||
|
|
||||||
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
if(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS)
|
||||||
|
if(FSFW_HAL_LINUX_ADD_LIBGPIOD)
|
||||||
add_subdirectory(gpio)
|
add_subdirectory(gpio)
|
||||||
|
endif()
|
||||||
add_subdirectory(spi)
|
add_subdirectory(spi)
|
||||||
add_subdirectory(i2c)
|
add_subdirectory(i2c)
|
||||||
add_subdirectory(uart)
|
add_subdirectory(uart)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(uio)
|
||||||
|
@ -44,6 +44,7 @@ ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
||||||
|
ReturnValue_t result = RETURN_OK;
|
||||||
for (auto& gpioConfig : mapToAdd) {
|
for (auto& gpioConfig : mapToAdd) {
|
||||||
auto& gpioType = gpioConfig.second->gpioType;
|
auto& gpioType = gpioConfig.second->gpioType;
|
||||||
switch (gpioType) {
|
switch (gpioType) {
|
||||||
@ -55,7 +56,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByChip(gpioConfig.first, *regularGpio);
|
result = configureGpioByChip(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
|
case (gpio::GpioTypes::GPIO_REGULAR_BY_LABEL): {
|
||||||
@ -63,7 +64,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByLabel(gpioConfig.first, *regularGpio);
|
result = configureGpioByLabel(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
case (gpio::GpioTypes::GPIO_REGULAR_BY_LINE_NAME): {
|
||||||
@ -71,7 +72,7 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
configureGpioByLineName(gpioConfig.first, *regularGpio);
|
result = configureGpioByLineName(gpioConfig.first, *regularGpio);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::GpioTypes::CALLBACK): {
|
case (gpio::GpioTypes::CALLBACK): {
|
||||||
@ -83,8 +84,11 @@ ReturnValue_t LinuxLibgpioIF::configureGpios(GpioMap& mapToAdd) {
|
|||||||
gpioCallback->initValue, gpioCallback->callbackArgs);
|
gpioCallback->initValue, gpioCallback->callbackArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (result != RETURN_OK) {
|
||||||
|
return GPIO_INIT_FAILED;
|
||||||
}
|
}
|
||||||
return RETURN_OK;
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
||||||
@ -161,11 +165,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
|||||||
consumer = regularGpio.consumer;
|
consumer = regularGpio.consumer;
|
||||||
/* Configure direction and add a description to the GPIO */
|
/* Configure direction and add a description to the GPIO */
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case (gpio::OUT): {
|
case (gpio::Direction::OUT): {
|
||||||
result = gpiod_line_request_output(lineHandle, consumer.c_str(), regularGpio.initValue);
|
result = gpiod_line_request_output(lineHandle, consumer.c_str(),
|
||||||
|
static_cast<int>(regularGpio.initValue));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (gpio::IN): {
|
case (gpio::Direction::IN): {
|
||||||
result = gpiod_line_request_input(lineHandle, consumer.c_str());
|
result = gpiod_line_request_input(lineHandle, consumer.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -211,7 +216,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_TYPE_FAILURE;
|
return GPIO_TYPE_FAILURE;
|
||||||
}
|
}
|
||||||
return driveGpio(gpioId, *regularGpio, gpio::HIGH);
|
return driveGpio(gpioId, *regularGpio, gpio::Levels::HIGH);
|
||||||
} else {
|
} else {
|
||||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||||
if (gpioCallback->callback == nullptr) {
|
if (gpioCallback->callback == nullptr) {
|
||||||
@ -243,7 +248,7 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
|||||||
if (regularGpio == nullptr) {
|
if (regularGpio == nullptr) {
|
||||||
return GPIO_TYPE_FAILURE;
|
return GPIO_TYPE_FAILURE;
|
||||||
}
|
}
|
||||||
return driveGpio(gpioId, *regularGpio, gpio::LOW);
|
return driveGpio(gpioId, *regularGpio, gpio::Levels::LOW);
|
||||||
} else {
|
} else {
|
||||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||||
if (gpioCallback->callback == nullptr) {
|
if (gpioCallback->callback == nullptr) {
|
||||||
@ -258,11 +263,11 @@ ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
|||||||
|
|
||||||
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio,
|
ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regularGpio,
|
||||||
gpio::Levels logicLevel) {
|
gpio::Levels logicLevel) {
|
||||||
int result = gpiod_line_set_value(regularGpio.lineHandle, logicLevel);
|
int result = gpiod_line_set_value(regularGpio.lineHandle, static_cast<int>(logicLevel));
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId
|
sif::warning << "LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID " << gpioId
|
||||||
<< " to logic level " << logicLevel << std::endl;
|
<< " to logic level " << static_cast<int>(logicLevel) << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning(
|
sif::printWarning(
|
||||||
"LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to "
|
"LinuxLibgpioIF::driveGpio: Failed to pull GPIO with ID %d to "
|
||||||
|
@ -29,6 +29,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
|||||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 4);
|
||||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED =
|
||||||
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 5);
|
||||||
|
static constexpr ReturnValue_t GPIO_INIT_FAILED =
|
||||||
|
HasReturnvaluesIF::makeReturnCode(gpioRetvalId, 6);
|
||||||
|
|
||||||
LinuxLibgpioIF(object_id_t objectId);
|
LinuxLibgpioIF(object_id_t objectId);
|
||||||
virtual ~LinuxLibgpioIF();
|
virtual ~LinuxLibgpioIF();
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
#include "fsfw_hal/linux/i2c/I2cComIF.h"
|
#include "I2cComIF.h"
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
#include "fsfw_hal/linux/UnixFileGuard.h"
|
||||||
|
#include "fsfw_hal/linux/utility.h"
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -8,11 +17,6 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/serviceinterface.h"
|
|
||||||
#include "fsfw_hal/linux/UnixFileGuard.h"
|
|
||||||
#include "fsfw_hal/linux/utility.h"
|
|
||||||
|
|
||||||
I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {}
|
I2cComIF::I2cComIF(object_id_t objectId) : SystemObject(objectId) {}
|
||||||
|
|
||||||
I2cComIF::~I2cComIF() {}
|
I2cComIF::~I2cComIF() {}
|
||||||
@ -112,6 +116,11 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
|
|||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl;
|
||||||
|
arrayprinter::print(sendData, sendLen);
|
||||||
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +185,11 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
|||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||||
|
sif::info << "I2C read bytes from bus " << deviceFile << ":" << std::endl;
|
||||||
|
arrayprinter::print(replyBuffer, requestLen);
|
||||||
|
#endif
|
||||||
|
|
||||||
i2cDeviceMapIter->second.replyLen = requestLen;
|
i2cDeviceMapIter->second.replyLen = requestLen;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
ReturnValue_t gpio::createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
||||||
std::string consumer, gpio::Direction direction,
|
std::string consumer, gpio::Direction direction,
|
||||||
int initValue) {
|
gpio::Levels initValue) {
|
||||||
if (cookie == nullptr) {
|
if (cookie == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ namespace gpio {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
ReturnValue_t createRpiGpioConfig(GpioCookie* cookie, gpioId_t gpioId, int bcmPin,
|
||||||
std::string consumer, gpio::Direction direction, int initValue);
|
std::string consumer, gpio::Direction direction,
|
||||||
|
gpio::Levels initValue);
|
||||||
} // namespace gpio
|
} // namespace gpio
|
||||||
|
|
||||||
#endif /* BSP_RPI_GPIO_GPIORPI_H_ */
|
#endif /* BSP_RPI_GPIO_GPIORPI_H_ */
|
||||||
|
@ -401,4 +401,12 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
|
|||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||||
}
|
}
|
||||||
|
// 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;
|
||||||
|
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||||
|
if (retval != 0) {
|
||||||
|
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
|||||||
MutexIF* spiMutex = nullptr;
|
MutexIF* spiMutex = nullptr;
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
uint32_t timeoutMs = 20;
|
uint32_t timeoutMs = 20;
|
||||||
|
spi_ioc_transfer clockUpdateTransfer = {};
|
||||||
|
|
||||||
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
||||||
using SpiDeviceMapIter = SpiDeviceMap::iterator;
|
using SpiDeviceMapIter = SpiDeviceMap::iterator;
|
||||||
|
@ -148,16 +148,16 @@ void UartComIF::setDatasizeOptions(struct termios* options, UartCookie* uartCook
|
|||||||
/* Clear size bits */
|
/* Clear size bits */
|
||||||
options->c_cflag &= ~CSIZE;
|
options->c_cflag &= ~CSIZE;
|
||||||
switch (uartCookie->getBitsPerWord()) {
|
switch (uartCookie->getBitsPerWord()) {
|
||||||
case 5:
|
case BitsPerWord::BITS_5:
|
||||||
options->c_cflag |= CS5;
|
options->c_cflag |= CS5;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case BitsPerWord::BITS_6:
|
||||||
options->c_cflag |= CS6;
|
options->c_cflag |= CS6;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case BitsPerWord::BITS_7:
|
||||||
options->c_cflag |= CS7;
|
options->c_cflag |= CS7;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case BitsPerWord::BITS_8:
|
||||||
options->c_cflag |= CS8;
|
options->c_cflag |= CS8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -193,82 +193,126 @@ void UartComIF::setFixedOptions(struct termios* options) {
|
|||||||
|
|
||||||
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
|
void UartComIF::configureBaudrate(struct termios* options, UartCookie* uartCookie) {
|
||||||
switch (uartCookie->getBaudrate()) {
|
switch (uartCookie->getBaudrate()) {
|
||||||
case 50:
|
case UartBaudRate::RATE_50:
|
||||||
cfsetispeed(options, B50);
|
cfsetispeed(options, B50);
|
||||||
cfsetospeed(options, B50);
|
cfsetospeed(options, B50);
|
||||||
break;
|
break;
|
||||||
case 75:
|
case UartBaudRate::RATE_75:
|
||||||
cfsetispeed(options, B75);
|
cfsetispeed(options, B75);
|
||||||
cfsetospeed(options, B75);
|
cfsetospeed(options, B75);
|
||||||
break;
|
break;
|
||||||
case 110:
|
case UartBaudRate::RATE_110:
|
||||||
cfsetispeed(options, B110);
|
cfsetispeed(options, B110);
|
||||||
cfsetospeed(options, B110);
|
cfsetospeed(options, B110);
|
||||||
break;
|
break;
|
||||||
case 134:
|
case UartBaudRate::RATE_134:
|
||||||
cfsetispeed(options, B134);
|
cfsetispeed(options, B134);
|
||||||
cfsetospeed(options, B134);
|
cfsetospeed(options, B134);
|
||||||
break;
|
break;
|
||||||
case 150:
|
case UartBaudRate::RATE_150:
|
||||||
cfsetispeed(options, B150);
|
cfsetispeed(options, B150);
|
||||||
cfsetospeed(options, B150);
|
cfsetospeed(options, B150);
|
||||||
break;
|
break;
|
||||||
case 200:
|
case UartBaudRate::RATE_200:
|
||||||
cfsetispeed(options, B200);
|
cfsetispeed(options, B200);
|
||||||
cfsetospeed(options, B200);
|
cfsetospeed(options, B200);
|
||||||
break;
|
break;
|
||||||
case 300:
|
case UartBaudRate::RATE_300:
|
||||||
cfsetispeed(options, B300);
|
cfsetispeed(options, B300);
|
||||||
cfsetospeed(options, B300);
|
cfsetospeed(options, B300);
|
||||||
break;
|
break;
|
||||||
case 600:
|
case UartBaudRate::RATE_600:
|
||||||
cfsetispeed(options, B600);
|
cfsetispeed(options, B600);
|
||||||
cfsetospeed(options, B600);
|
cfsetospeed(options, B600);
|
||||||
break;
|
break;
|
||||||
case 1200:
|
case UartBaudRate::RATE_1200:
|
||||||
cfsetispeed(options, B1200);
|
cfsetispeed(options, B1200);
|
||||||
cfsetospeed(options, B1200);
|
cfsetospeed(options, B1200);
|
||||||
break;
|
break;
|
||||||
case 1800:
|
case UartBaudRate::RATE_1800:
|
||||||
cfsetispeed(options, B1800);
|
cfsetispeed(options, B1800);
|
||||||
cfsetospeed(options, B1800);
|
cfsetospeed(options, B1800);
|
||||||
break;
|
break;
|
||||||
case 2400:
|
case UartBaudRate::RATE_2400:
|
||||||
cfsetispeed(options, B2400);
|
cfsetispeed(options, B2400);
|
||||||
cfsetospeed(options, B2400);
|
cfsetospeed(options, B2400);
|
||||||
break;
|
break;
|
||||||
case 4800:
|
case UartBaudRate::RATE_4800:
|
||||||
cfsetispeed(options, B4800);
|
cfsetispeed(options, B4800);
|
||||||
cfsetospeed(options, B4800);
|
cfsetospeed(options, B4800);
|
||||||
break;
|
break;
|
||||||
case 9600:
|
case UartBaudRate::RATE_9600:
|
||||||
cfsetispeed(options, B9600);
|
cfsetispeed(options, B9600);
|
||||||
cfsetospeed(options, B9600);
|
cfsetospeed(options, B9600);
|
||||||
break;
|
break;
|
||||||
case 19200:
|
case UartBaudRate::RATE_19200:
|
||||||
cfsetispeed(options, B19200);
|
cfsetispeed(options, B19200);
|
||||||
cfsetospeed(options, B19200);
|
cfsetospeed(options, B19200);
|
||||||
break;
|
break;
|
||||||
case 38400:
|
case UartBaudRate::RATE_38400:
|
||||||
cfsetispeed(options, B38400);
|
cfsetispeed(options, B38400);
|
||||||
cfsetospeed(options, B38400);
|
cfsetospeed(options, B38400);
|
||||||
break;
|
break;
|
||||||
case 57600:
|
case UartBaudRate::RATE_57600:
|
||||||
cfsetispeed(options, B57600);
|
cfsetispeed(options, B57600);
|
||||||
cfsetospeed(options, B57600);
|
cfsetospeed(options, B57600);
|
||||||
break;
|
break;
|
||||||
case 115200:
|
case UartBaudRate::RATE_115200:
|
||||||
cfsetispeed(options, B115200);
|
cfsetispeed(options, B115200);
|
||||||
cfsetospeed(options, B115200);
|
cfsetospeed(options, B115200);
|
||||||
break;
|
break;
|
||||||
case 230400:
|
case UartBaudRate::RATE_230400:
|
||||||
cfsetispeed(options, B230400);
|
cfsetispeed(options, B230400);
|
||||||
cfsetospeed(options, B230400);
|
cfsetospeed(options, B230400);
|
||||||
break;
|
break;
|
||||||
case 460800:
|
case UartBaudRate::RATE_460800:
|
||||||
cfsetispeed(options, B460800);
|
cfsetispeed(options, B460800);
|
||||||
cfsetospeed(options, B460800);
|
cfsetospeed(options, B460800);
|
||||||
break;
|
break;
|
||||||
|
case UartBaudRate::RATE_500000:
|
||||||
|
cfsetispeed(options, B500000);
|
||||||
|
cfsetospeed(options, B500000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_576000:
|
||||||
|
cfsetispeed(options, B576000);
|
||||||
|
cfsetospeed(options, B576000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_921600:
|
||||||
|
cfsetispeed(options, B921600);
|
||||||
|
cfsetospeed(options, B921600);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_1000000:
|
||||||
|
cfsetispeed(options, B1000000);
|
||||||
|
cfsetospeed(options, B1000000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_1152000:
|
||||||
|
cfsetispeed(options, B1152000);
|
||||||
|
cfsetospeed(options, B1152000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_1500000:
|
||||||
|
cfsetispeed(options, B1500000);
|
||||||
|
cfsetospeed(options, B1500000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_2000000:
|
||||||
|
cfsetispeed(options, B2000000);
|
||||||
|
cfsetospeed(options, B2000000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_2500000:
|
||||||
|
cfsetispeed(options, B2500000);
|
||||||
|
cfsetospeed(options, B2500000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_3000000:
|
||||||
|
cfsetispeed(options, B3000000);
|
||||||
|
cfsetospeed(options, B3000000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_3500000:
|
||||||
|
cfsetispeed(options, B3500000);
|
||||||
|
cfsetospeed(options, B3500000);
|
||||||
|
break;
|
||||||
|
case UartBaudRate::RATE_4000000:
|
||||||
|
cfsetispeed(options, B4000000);
|
||||||
|
cfsetospeed(options, B4000000);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
sif::warning << "UartComIF::configureBaudrate: Baudrate not supported" << std::endl;
|
||||||
@ -427,7 +471,7 @@ ReturnValue_t UartComIF::handleNoncanonicalRead(UartCookie& uartCookie, UartDevi
|
|||||||
auto bufferPtr = iter->second.replyBuffer.data();
|
auto bufferPtr = iter->second.replyBuffer.data();
|
||||||
// Size check to prevent buffer overflow
|
// Size check to prevent buffer overflow
|
||||||
if (requestLen > uartCookie.getMaxReplyLen()) {
|
if (requestLen > uartCookie.getMaxReplyLen()) {
|
||||||
#if OBSW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!"
|
sif::warning << "UartComIF::requestReceiveMessage: Next read would cause overflow!"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#include "fsfw_hal/linux/uart/UartCookie.h"
|
#include "UartCookie.h"
|
||||||
|
|
||||||
#include <fsfw/serviceinterface.h>
|
#include <fsfw/serviceinterface.h>
|
||||||
|
|
||||||
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||||
uint32_t baudrate, size_t maxReplyLen)
|
UartBaudRate baudrate, size_t maxReplyLen)
|
||||||
: handlerId(handlerId),
|
: handlerId(handlerId),
|
||||||
deviceFile(deviceFile),
|
deviceFile(deviceFile),
|
||||||
uartMode(uartMode),
|
uartMode(uartMode),
|
||||||
@ -12,7 +12,7 @@ UartCookie::UartCookie(object_id_t handlerId, std::string deviceFile, UartModes
|
|||||||
|
|
||||||
UartCookie::~UartCookie() {}
|
UartCookie::~UartCookie() {}
|
||||||
|
|
||||||
uint32_t UartCookie::getBaudrate() const { return baudrate; }
|
UartBaudRate UartCookie::getBaudrate() const { return baudrate; }
|
||||||
|
|
||||||
size_t UartCookie::getMaxReplyLen() const { return maxReplyLen; }
|
size_t UartCookie::getMaxReplyLen() const { return maxReplyLen; }
|
||||||
|
|
||||||
@ -24,23 +24,9 @@ void UartCookie::setParityEven() { parity = Parity::EVEN; }
|
|||||||
|
|
||||||
Parity UartCookie::getParity() const { return parity; }
|
Parity UartCookie::getParity() const { return parity; }
|
||||||
|
|
||||||
void UartCookie::setBitsPerWord(uint8_t bitsPerWord_) {
|
void UartCookie::setBitsPerWord(BitsPerWord bitsPerWord_) { bitsPerWord = bitsPerWord_; }
|
||||||
switch (bitsPerWord_) {
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "UartCookie::setBitsPerWord: Invalid bits per word specified" << std::endl;
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bitsPerWord = bitsPerWord_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t UartCookie::getBitsPerWord() const { return bitsPerWord; }
|
BitsPerWord UartCookie::getBitsPerWord() const { return bitsPerWord; }
|
||||||
|
|
||||||
StopBits UartCookie::getStopBits() const { return stopBits; }
|
StopBits UartCookie::getStopBits() const { return stopBits; }
|
||||||
|
|
||||||
|
@ -12,6 +12,41 @@ enum class StopBits { ONE_STOP_BIT, TWO_STOP_BITS };
|
|||||||
|
|
||||||
enum class UartModes { CANONICAL, NON_CANONICAL };
|
enum class UartModes { CANONICAL, NON_CANONICAL };
|
||||||
|
|
||||||
|
enum class BitsPerWord { BITS_5, BITS_6, BITS_7, BITS_8 };
|
||||||
|
|
||||||
|
enum class UartBaudRate {
|
||||||
|
RATE_50,
|
||||||
|
RATE_75,
|
||||||
|
RATE_110,
|
||||||
|
RATE_134,
|
||||||
|
RATE_150,
|
||||||
|
RATE_200,
|
||||||
|
RATE_300,
|
||||||
|
RATE_600,
|
||||||
|
RATE_1200,
|
||||||
|
RATE_1800,
|
||||||
|
RATE_2400,
|
||||||
|
RATE_4800,
|
||||||
|
RATE_9600,
|
||||||
|
RATE_19200,
|
||||||
|
RATE_38400,
|
||||||
|
RATE_57600,
|
||||||
|
RATE_115200,
|
||||||
|
RATE_230400,
|
||||||
|
RATE_460800,
|
||||||
|
RATE_500000,
|
||||||
|
RATE_576000,
|
||||||
|
RATE_921600,
|
||||||
|
RATE_1000000,
|
||||||
|
RATE_1152000,
|
||||||
|
RATE_1500000,
|
||||||
|
RATE_2000000,
|
||||||
|
RATE_2500000,
|
||||||
|
RATE_3000000,
|
||||||
|
RATE_3500000,
|
||||||
|
RATE_4000000
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cookie for the UartComIF. There are many options available to configure the UART driver.
|
* @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
|
* The constructor only requests for common options like the baudrate. Other options can
|
||||||
@ -27,25 +62,23 @@ class UartCookie : public CookieIF {
|
|||||||
* @param uartMode Specify the UART mode. The canonical mode should be used if the
|
* @param uartMode Specify the UART mode. The canonical mode should be used if the
|
||||||
* messages are separated by a delimited character like '\n'. See the
|
* messages are separated by a delimited character like '\n'. See the
|
||||||
* termios documentation for more information
|
* termios documentation for more information
|
||||||
* @param baudrate The baudrate to use for input and output. Possible Baudrates are: 50,
|
* @param baudrate The baudrate to use for input and output.
|
||||||
* 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, B19200,
|
|
||||||
* 38400, 57600, 115200, 230400, 460800
|
|
||||||
* @param maxReplyLen The maximum size an object using this cookie expects
|
* @param maxReplyLen The maximum size an object using this cookie expects
|
||||||
* @details
|
* @details
|
||||||
* Default configuration: No parity
|
* Default configuration: No parity
|
||||||
* 8 databits (number of bits transfered with one uart frame)
|
* 8 databits (number of bits transfered with one uart frame)
|
||||||
* One stop bit
|
* One stop bit
|
||||||
*/
|
*/
|
||||||
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode, uint32_t baudrate,
|
UartCookie(object_id_t handlerId, std::string deviceFile, UartModes uartMode,
|
||||||
size_t maxReplyLen);
|
UartBaudRate baudrate, size_t maxReplyLen);
|
||||||
|
|
||||||
virtual ~UartCookie();
|
virtual ~UartCookie();
|
||||||
|
|
||||||
uint32_t getBaudrate() const;
|
UartBaudRate getBaudrate() const;
|
||||||
size_t getMaxReplyLen() const;
|
size_t getMaxReplyLen() const;
|
||||||
std::string getDeviceFile() const;
|
std::string getDeviceFile() const;
|
||||||
Parity getParity() const;
|
Parity getParity() const;
|
||||||
uint8_t getBitsPerWord() const;
|
BitsPerWord getBitsPerWord() const;
|
||||||
StopBits getStopBits() const;
|
StopBits getStopBits() const;
|
||||||
UartModes getUartMode() const;
|
UartModes getUartMode() const;
|
||||||
object_id_t getHandlerId() const;
|
object_id_t getHandlerId() const;
|
||||||
@ -76,7 +109,7 @@ class UartCookie : public CookieIF {
|
|||||||
/**
|
/**
|
||||||
* Function two set number of bits per UART frame.
|
* Function two set number of bits per UART frame.
|
||||||
*/
|
*/
|
||||||
void setBitsPerWord(uint8_t bitsPerWord_);
|
void setBitsPerWord(BitsPerWord bitsPerWord_);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to specify the number of stopbits.
|
* Function to specify the number of stopbits.
|
||||||
@ -97,10 +130,10 @@ class UartCookie : public CookieIF {
|
|||||||
std::string deviceFile;
|
std::string deviceFile;
|
||||||
const UartModes uartMode;
|
const UartModes uartMode;
|
||||||
bool flushInput = false;
|
bool flushInput = false;
|
||||||
uint32_t baudrate;
|
UartBaudRate baudrate;
|
||||||
size_t maxReplyLen = 0;
|
size_t maxReplyLen = 0;
|
||||||
Parity parity = Parity::NONE;
|
Parity parity = Parity::NONE;
|
||||||
uint8_t bitsPerWord = 8;
|
BitsPerWord bitsPerWord = BitsPerWord::BITS_8;
|
||||||
uint8_t readCycles = 1;
|
uint8_t readCycles = 1;
|
||||||
StopBits stopBits = StopBits::ONE_STOP_BIT;
|
StopBits stopBits = StopBits::ONE_STOP_BIT;
|
||||||
bool replySizeFixed = true;
|
bool replySizeFixed = true;
|
||||||
|
3
hal/src/fsfw_hal/linux/uio/CMakeLists.txt
Normal file
3
hal/src/fsfw_hal/linux/uio/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target_sources(${LIB_FSFW_NAME} PUBLIC
|
||||||
|
UioMapper.cpp
|
||||||
|
)
|
86
hal/src/fsfw_hal/linux/uio/UioMapper.cpp
Normal file
86
hal/src/fsfw_hal/linux/uio/UioMapper.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "UioMapper.h"
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
|
const char UioMapper::UIO_PATH_PREFIX[] = "/sys/class/uio/";
|
||||||
|
const char UioMapper::MAP_SUBSTR[] = "/maps/map";
|
||||||
|
const char UioMapper::SIZE_FILE_PATH[] = "/size";
|
||||||
|
|
||||||
|
UioMapper::UioMapper(std::string uioFile, int mapNum) : uioFile(uioFile), mapNum(mapNum) {}
|
||||||
|
|
||||||
|
UioMapper::~UioMapper() {}
|
||||||
|
|
||||||
|
ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permissions) {
|
||||||
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
|
||||||
|
int fd = open(uioFile.c_str(), O_RDWR);
|
||||||
|
if (fd < 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "PtmeAxiConfig::initialize: Invalid UIO device file" << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
size_t size = 0;
|
||||||
|
result = getMapSize(&size);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*address = static_cast<uint32_t*>(
|
||||||
|
mmap(NULL, size, static_cast<int>(permissions), MAP_SHARED, fd, mapNum * getpagesize()));
|
||||||
|
|
||||||
|
if (*address == MAP_FAILED) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UioMapper::getMappedAdress: Failed to map physical address of uio device "
|
||||||
|
<< uioFile.c_str() << " and map" << static_cast<int>(mapNum) << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t UioMapper::getMapSize(size_t* size) {
|
||||||
|
std::stringstream namestream;
|
||||||
|
namestream << UIO_PATH_PREFIX << uioFile.substr(5, std::string::npos) << MAP_SUBSTR << mapNum
|
||||||
|
<< SIZE_FILE_PATH;
|
||||||
|
FILE* fp;
|
||||||
|
fp = fopen(namestream.str().c_str(), "r");
|
||||||
|
if (fp == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UioMapper::getMapSize: Failed to open file " << namestream.str() << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
char hexstring[SIZE_HEX_STRING] = "";
|
||||||
|
int items = fscanf(fp, "%s", hexstring);
|
||||||
|
if (items != 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UioMapper::getMapSize: Failed with error code " << errno
|
||||||
|
<< " to read size "
|
||||||
|
"string from file "
|
||||||
|
<< namestream.str() << std::endl;
|
||||||
|
#endif
|
||||||
|
fclose(fp);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
uint32_t sizeTmp = 0;
|
||||||
|
items = sscanf(hexstring, "%x", &sizeTmp);
|
||||||
|
if (size != nullptr) {
|
||||||
|
*size = sizeTmp;
|
||||||
|
}
|
||||||
|
if (items != 1) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "UioMapper::getMapSize: Failed with error code " << errno << "to convert "
|
||||||
|
<< "size of map" << mapNum << " to integer" << std::endl;
|
||||||
|
#endif
|
||||||
|
fclose(fp);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
58
hal/src/fsfw_hal/linux/uio/UioMapper.h
Normal file
58
hal/src/fsfw_hal/linux/uio/UioMapper.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_
|
||||||
|
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to help opening uio device files and mapping the physical addresses into the user
|
||||||
|
* address space.
|
||||||
|
*
|
||||||
|
* @author J. Meier
|
||||||
|
*/
|
||||||
|
class UioMapper {
|
||||||
|
public:
|
||||||
|
enum class Permissions : int {
|
||||||
|
READ_ONLY = PROT_READ,
|
||||||
|
WRITE_ONLY = PROT_WRITE,
|
||||||
|
READ_WRITE = PROT_READ | PROT_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*
|
||||||
|
* @param uioFile The device file of the uiO to open
|
||||||
|
* @param uioMap Number of memory map. Most UIO drivers have only one map which has than 0.
|
||||||
|
*/
|
||||||
|
UioMapper(std::string uioFile, int mapNum = 0);
|
||||||
|
virtual ~UioMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maps the physical address into user address space and returns the mapped address
|
||||||
|
*
|
||||||
|
* @address The mapped user space address
|
||||||
|
* @permissions Specifies the read/write permissions of the address region
|
||||||
|
*/
|
||||||
|
ReturnValue_t getMappedAdress(uint32_t** address, Permissions permissions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char UIO_PATH_PREFIX[];
|
||||||
|
static const char MAP_SUBSTR[];
|
||||||
|
static const char SIZE_FILE_PATH[];
|
||||||
|
static constexpr int SIZE_HEX_STRING = 10;
|
||||||
|
|
||||||
|
std::string uioFile;
|
||||||
|
int mapNum = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads the map size from the associated sysfs size file
|
||||||
|
*
|
||||||
|
* @param size The read map size
|
||||||
|
*/
|
||||||
|
ReturnValue_t getMapSize(size_t* size);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_UIO_UIOMAPPER_H_ */
|
@ -21,7 +21,7 @@ using mspCb = void (*)(void);
|
|||||||
namespace spi {
|
namespace spi {
|
||||||
|
|
||||||
struct MspCfgBase {
|
struct MspCfgBase {
|
||||||
MspCfgBase();
|
MspCfgBase() {}
|
||||||
MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
MspCfgBase(stm32h7::GpioCfg sck, stm32h7::GpioCfg mosi, stm32h7::GpioCfg miso,
|
||||||
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
mspCb cleanupCb = nullptr, mspCb setupCb = nullptr)
|
||||||
: sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), setupCb(setupCb) {}
|
: sck(sck), mosi(mosi), miso(miso), cleanupCb(cleanupCb), setupCb(setupCb) {}
|
||||||
|
@ -97,11 +97,11 @@ def handle_docs_type(args, build_dir_list: list):
|
|||||||
build_directory = determine_build_dir(build_dir_list)
|
build_directory = determine_build_dir(build_dir_list)
|
||||||
os.chdir(build_directory)
|
os.chdir(build_directory)
|
||||||
if args.build:
|
if args.build:
|
||||||
os.system("cmake --build . -j")
|
cmd_runner("cmake --build . -j")
|
||||||
if args.open:
|
if args.open:
|
||||||
if not os.path.isfile("docs/sphinx/index.html"):
|
if not os.path.isfile("docs/sphinx/index.html"):
|
||||||
# try again..
|
# try again..
|
||||||
os.system("cmake --build . -j")
|
cmd_runner("cmake --build . -j")
|
||||||
if not os.path.isfile("docs/sphinx/index.html"):
|
if not os.path.isfile("docs/sphinx/index.html"):
|
||||||
print(
|
print(
|
||||||
"No Sphinx documentation file detected. "
|
"No Sphinx documentation file detected. "
|
||||||
@ -143,22 +143,21 @@ def handle_tests_type(args, build_dir_list: list):
|
|||||||
if which("valgrind") is None:
|
if which("valgrind") is None:
|
||||||
print("Please install valgrind first")
|
print("Please install valgrind first")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
os.chdir(UNITTEST_FOLDER_NAME)
|
cmd_runner("valgrind --leak-check=full ./fsfw-tests")
|
||||||
os.system("valgrind --leak-check=full ./fsfw-tests")
|
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def create_tests_build_cfg():
|
def create_tests_build_cfg():
|
||||||
os.mkdir(UNITTEST_FOLDER_NAME)
|
os.mkdir(UNITTEST_FOLDER_NAME)
|
||||||
os.chdir(UNITTEST_FOLDER_NAME)
|
os.chdir(UNITTEST_FOLDER_NAME)
|
||||||
os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..")
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
def create_docs_build_cfg():
|
def create_docs_build_cfg():
|
||||||
os.mkdir(DOCS_FOLDER_NAME)
|
os.mkdir(DOCS_FOLDER_NAME)
|
||||||
os.chdir(DOCS_FOLDER_NAME)
|
os.chdir(DOCS_FOLDER_NAME)
|
||||||
os.system("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..")
|
cmd_runner("cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..")
|
||||||
os.chdir("..")
|
os.chdir("..")
|
||||||
|
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ def check_for_cmake_build_dir(build_dir_list: list) -> list:
|
|||||||
def perform_lcov_operation(directory: str, chdir: bool):
|
def perform_lcov_operation(directory: str, chdir: bool):
|
||||||
if chdir:
|
if chdir:
|
||||||
os.chdir(directory)
|
os.chdir(directory)
|
||||||
os.system("cmake --build . -- fsfw-tests_coverage -j")
|
cmd_runner("cmake --build . -- fsfw-tests_coverage -j")
|
||||||
|
|
||||||
|
|
||||||
def determine_build_dir(build_dir_list: List[str]):
|
def determine_build_dir(build_dir_list: List[str]):
|
||||||
@ -203,5 +202,10 @@ def determine_build_dir(build_dir_list: List[str]):
|
|||||||
return build_directory
|
return build_directory
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_runner(cmd: str):
|
||||||
|
print(f"Executing command: {cmd}")
|
||||||
|
os.system(cmd)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
version.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
|
|
||||||
add_subdirectory(action)
|
add_subdirectory(action)
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
#define FSFW_VERBOSE_LEVEL 1
|
#define FSFW_VERBOSE_LEVEL 1
|
||||||
#endif /* FSFW_VERBOSE_LEVEL */
|
#endif /* FSFW_VERBOSE_LEVEL */
|
||||||
|
|
||||||
|
#ifndef FSFW_DISABLE_PRINTOUT
|
||||||
|
#define FSFW_DISABLE_PRINTOUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
||||||
#define FSFW_USE_REALTIME_FOR_LINUX 0
|
#define FSFW_USE_REALTIME_FOR_LINUX 0
|
||||||
#endif /* FSFW_USE_REALTIME_FOR_LINUX */
|
#endif /* FSFW_USE_REALTIME_FOR_LINUX */
|
||||||
@ -57,16 +61,9 @@
|
|||||||
#define FSFW_HAL_SPI_WIRETAPPING 0
|
#define FSFW_HAL_SPI_WIRETAPPING 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FSFW_HAL_L3GD20_GYRO_DEBUG
|
// Can be used for low-level debugging of the I2C bus
|
||||||
#define FSFW_HAL_L3GD20_GYRO_DEBUG 0
|
#ifndef FSFW_HAL_I2C_WIRETAPPING
|
||||||
#endif /* FSFW_HAL_L3GD20_GYRO_DEBUG */
|
#define FSFW_HAL_I2C_WIRETAPPING 0
|
||||||
|
#endif
|
||||||
#ifndef FSFW_HAL_RM3100_MGM_DEBUG
|
|
||||||
#define FSFW_HAL_RM3100_MGM_DEBUG 0
|
|
||||||
#endif /* FSFW_HAL_RM3100_MGM_DEBUG */
|
|
||||||
|
|
||||||
#ifndef FSFW_HAL_LIS3MDL_MGM_DEBUG
|
|
||||||
#define FSFW_HAL_LIS3MDL_MGM_DEBUG 0
|
|
||||||
#endif /* FSFW_HAL_LIS3MDL_MGM_DEBUG */
|
|
||||||
|
|
||||||
#endif /* FSFW_FSFW_H_ */
|
#endif /* FSFW_FSFW_H_ */
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#define FSFW_VERSION_H_
|
#define FSFW_VERSION_H_
|
||||||
|
|
||||||
// Versioning is kept in project CMakeLists.txt file
|
// Versioning is kept in project CMakeLists.txt file
|
||||||
#define FSFW_VERSION @FSFW_VERSION@
|
#define FSFW_VERSION_MAJOR @FSFW_VERSION@
|
||||||
#define FSFW_SUBVERSION @FSFW_SUBVERSION@
|
#define FSFW_VERSION_MINOR @FSFW_SUBVERSION@
|
||||||
#define FSFW_REVISION @FSFW_REVISION@
|
#define FSFW_VERSION_REVISION @FSFW_REVISION@
|
||||||
|
|
||||||
#endif /* FSFW_VERSION_H_ */
|
#endif /* FSFW_VERSION_H_ */
|
||||||
|
@ -6,10 +6,13 @@
|
|||||||
#include <fsfw/cfdp/tlv/Tlv.h>
|
#include <fsfw/cfdp/tlv/Tlv.h>
|
||||||
#include <fsfw/cfdp/tlv/TlvIF.h>
|
#include <fsfw/cfdp/tlv/TlvIF.h>
|
||||||
#include <fsfw/serialize/SerializeIF.h>
|
#include <fsfw/serialize/SerializeIF.h>
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
|
||||||
namespace cfdp {
|
namespace cfdp {
|
||||||
|
|
||||||
enum FilestoreActionCode {
|
enum FilestoreActionCode {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||||
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
|
||||||
|
|
||||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
|
||||||
#include "fsfw/health/HasHealthIF.h"
|
#include "fsfw/health/HasHealthIF.h"
|
||||||
#include "fsfw/health/HealthHelper.h"
|
#include "fsfw/health/HealthHelper.h"
|
||||||
#include "fsfw/modes/HasModesIF.h"
|
#include "fsfw/modes/HasModesIF.h"
|
||||||
|
@ -30,7 +30,7 @@ class DataLinkLayer : public CCSDSReturnValuesIF {
|
|||||||
//! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
|
//! [EXPORT] : [COMMENT] A previously found Bit Lock signal was lost. P1: raw BLO state, P2: 0
|
||||||
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO);
|
static const Event BIT_LOCK_LOST = MAKE_EVENT(3, severity::INFO);
|
||||||
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board
|
// static const Event RF_CHAIN_LOST = MAKE_EVENT(4, severity::INFO); //!< The CCSDS Board
|
||||||
//detected that either bit lock or RF available or both are lost. No parameters.
|
// detected that either bit lock or RF available or both are lost. No parameters.
|
||||||
//! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC
|
//! [EXPORT] : [COMMENT] The CCSDS Board could not interpret a TC
|
||||||
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW);
|
static const Event FRAME_PROCESSING_FAILED = MAKE_EVENT(5, severity::LOW);
|
||||||
/**
|
/**
|
||||||
|
@ -30,9 +30,9 @@ ReturnValue_t VirtualChannelReception::mapDemultiplexing(TcTransferFrame* frame)
|
|||||||
mapChannelIterator iter = mapChannels.find(mapId);
|
mapChannelIterator iter = mapChannels.find(mapId);
|
||||||
if (iter == mapChannels.end()) {
|
if (iter == mapChannels.end()) {
|
||||||
// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int)
|
// error << "VirtualChannelReception::mapDemultiplexing on VC " << std::hex << (int)
|
||||||
//channelId
|
// channelId
|
||||||
// << ": MapChannel " << (int) mapId << std::dec << " not found." <<
|
// << ": MapChannel " << (int) mapId << std::dec << " not found." <<
|
||||||
//std::endl;
|
// std::endl;
|
||||||
return VC_NOT_FOUND;
|
return VC_NOT_FOUND;
|
||||||
} else {
|
} else {
|
||||||
return (iter->second)->extractPackets(frame);
|
return (iter->second)->extractPackets(frame);
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
HkSwitchHelper.cpp
|
|
||||||
PoolDataSetBase.cpp
|
PoolDataSetBase.cpp
|
||||||
PoolEntry.cpp
|
PoolEntry.cpp
|
||||||
)
|
)
|
@ -1,67 +0,0 @@
|
|||||||
#include "fsfw/datapool/HkSwitchHelper.h"
|
|
||||||
|
|
||||||
#include "fsfw/ipc/QueueFactory.h"
|
|
||||||
|
|
||||||
HkSwitchHelper::HkSwitchHelper(EventReportingProxyIF* eventProxy)
|
|
||||||
: commandActionHelper(this), eventProxy(eventProxy) {
|
|
||||||
actionQueue = QueueFactory::instance()->createMessageQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
HkSwitchHelper::~HkSwitchHelper() { QueueFactory::instance()->deleteMessageQueue(actionQueue); }
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::initialize() {
|
|
||||||
ReturnValue_t result = commandActionHelper.initialize();
|
|
||||||
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::performOperation(uint8_t operationCode) {
|
|
||||||
CommandMessage command;
|
|
||||||
while (actionQueue->receiveMessage(&command) == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
ReturnValue_t result = commandActionHelper.handleReply(&command);
|
|
||||||
if (result == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
command.setToUnknownCommand();
|
|
||||||
actionQueue->reply(&command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::stepFailedReceived(ActionId_t actionId, uint8_t step,
|
|
||||||
ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HkSwitchHelper::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionSuccessfulReceived(ActionId_t actionId) {}
|
|
||||||
|
|
||||||
void HkSwitchHelper::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) {
|
|
||||||
eventProxy->forwardEvent(SWITCHING_TM_FAILED, returnCode, actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t HkSwitchHelper::switchHK(SerializeIF* sids, bool enable) {
|
|
||||||
// ActionId_t action = HKService::DISABLE_HK;
|
|
||||||
// if (enable) {
|
|
||||||
// action = HKService::ENABLE_HK;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ReturnValue_t result = commandActionHelper.commandAction(
|
|
||||||
// objects::PUS_HK_SERVICE, action, sids);
|
|
||||||
//
|
|
||||||
// if (result != HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
// eventProxy->forwardEvent(SWITCHING_TM_FAILED, result);
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueIF* HkSwitchHelper::getCommandQueuePtr() { return actionQueue; }
|
|
@ -1,44 +0,0 @@
|
|||||||
#ifndef FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
#define FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_
|
|
||||||
|
|
||||||
#include "fsfw/action/CommandsActionsIF.h"
|
|
||||||
#include "fsfw/events/EventReportingProxyIF.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
|
||||||
|
|
||||||
// TODO this class violations separation between mission and framework
|
|
||||||
// but it is only a transitional solution until the Datapool is
|
|
||||||
// implemented decentrally
|
|
||||||
|
|
||||||
class HkSwitchHelper : public ExecutableObjectIF, public CommandsActionsIF {
|
|
||||||
public:
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::HK;
|
|
||||||
static const Event SWITCHING_TM_FAILED =
|
|
||||||
MAKE_EVENT(1, severity::LOW); //!< Commanding the HK Service failed, p1: error code, p2
|
|
||||||
//!< action: 0 disable / 1 enable
|
|
||||||
|
|
||||||
HkSwitchHelper(EventReportingProxyIF* eventProxy);
|
|
||||||
virtual ~HkSwitchHelper();
|
|
||||||
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
|
|
||||||
virtual ReturnValue_t performOperation(uint8_t operationCode = 0);
|
|
||||||
|
|
||||||
ReturnValue_t switchHK(SerializeIF* sids, bool enable);
|
|
||||||
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task_){};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step);
|
|
||||||
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode);
|
|
||||||
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size);
|
|
||||||
virtual void completionSuccessfulReceived(ActionId_t actionId);
|
|
||||||
virtual void completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode);
|
|
||||||
virtual MessageQueueIF* getCommandQueuePtr();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CommandActionHelper commandActionHelper;
|
|
||||||
MessageQueueIF* actionQueue;
|
|
||||||
EventReportingProxyIF* eventProxy;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_DATAPOOL_HKSWITCHHELPER_H_ */
|
|
@ -84,8 +84,8 @@ ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initialize", HasReturnvaluesIF::RETURN_FAILED,
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "initializeHousekeepingPoolEntriesOnce",
|
||||||
"The map should only be initialized once");
|
HasReturnvaluesIF::RETURN_FAILED, "The map should only be initialized once");
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,6 +787,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
|||||||
// Serialize set packet into store.
|
// Serialize set packet into store.
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG);
|
result = setPacket.serialize(&storePtr, &size, expectedSize, SerializeIF::Endianness::BIG);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ipcStore->deleteData(storeId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
if (expectedSize != size) {
|
if (expectedSize != size) {
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket",
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "generateSetStructurePacket",
|
||||||
HasReturnvaluesIF::RETURN_FAILED,
|
HasReturnvaluesIF::RETURN_FAILED,
|
||||||
@ -801,7 +805,10 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid, bool i
|
|||||||
HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId);
|
HousekeepingMessage::setHkStuctureReportReply(&reply, sid, storeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
hkQueue->reply(&reply);
|
result = hkQueue->reply(&reply);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
ipcStore->deleteData(storeId);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,13 +47,14 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
|
|||||||
HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(poolOwner);
|
HasLocalDataPoolIF* hkOwner = ObjectManager::instance()->get<HasLocalDataPoolIF>(poolOwner);
|
||||||
if (hkOwner == nullptr) {
|
if (hkOwner == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "
|
sif::error << "LocalPoolVariable: The supplied pool owner 0x" << std::hex << poolOwner
|
||||||
"interface HasLocalDataPoolIF!"
|
<< std::dec << " did not implement the correct interface "
|
||||||
<< std::endl;
|
<< "HasLocalDataPoolIF" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError(
|
sif::printError(
|
||||||
"LocalPoolVariable: The supplied pool owner did not implement the correct "
|
"LocalPoolVariable: The supplied pool owner 0x%08x did not implement the correct "
|
||||||
"interface HasLocalDataPoolIF!\n");
|
"interface HasLocalDataPoolIF\n",
|
||||||
|
poolOwner);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class StaticLocalDataSet : public LocalPoolDataSetBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<PoolVariableIF*, NUM_VARIABLES> poolVarList;
|
std::array<PoolVariableIF*, NUM_VARIABLES> poolVarList = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */
|
#endif /* FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ */
|
||||||
|
@ -410,7 +410,7 @@ ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
|
|||||||
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles, LocalPoolDataSetBase* replyDataSet,
|
||||||
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
size_t replyLen, bool periodic, bool hasDifferentReplyId, DeviceCommandId_t replyId) {
|
||||||
// No need to check, as we may try to insert multiple times.
|
// No need to check, as we may try to insert multiple times.
|
||||||
insertInCommandMap(deviceCommand);
|
insertInCommandMap(deviceCommand, hasDifferentReplyId, replyId);
|
||||||
if (hasDifferentReplyId) {
|
if (hasDifferentReplyId) {
|
||||||
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
return insertInReplyMap(replyId, maxDelayCycles, replyDataSet, replyLen, periodic);
|
||||||
} else {
|
} else {
|
||||||
@ -437,11 +437,15 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) {
|
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand,
|
||||||
|
bool useAlternativeReply,
|
||||||
|
DeviceCommandId_t alternativeReplyId) {
|
||||||
DeviceCommandInfo info;
|
DeviceCommandInfo info;
|
||||||
info.expectedReplies = 0;
|
info.expectedReplies = 0;
|
||||||
info.isExecuting = false;
|
info.isExecuting = false;
|
||||||
info.sendReplyTo = NO_COMMANDER;
|
info.sendReplyTo = NO_COMMANDER;
|
||||||
|
info.useAlternativeReplyId = alternativeReplyId;
|
||||||
|
info.alternativeReplyId = alternativeReplyId;
|
||||||
auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
|
auto resultPair = deviceCommandMap.emplace(deviceCommand, info);
|
||||||
if (resultPair.second) {
|
if (resultPair.second) {
|
||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
@ -451,12 +455,20 @@ ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceComm
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
size_t DeviceHandlerBase::getNextReplyLength(DeviceCommandId_t commandId) {
|
||||||
DeviceReplyIter iter = deviceReplyMap.find(commandId);
|
DeviceCommandId_t replyId = NO_COMMAND_ID;
|
||||||
if (iter != deviceReplyMap.end()) {
|
DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
|
||||||
return iter->second.replyLen;
|
if (command->second.useAlternativeReplyId) {
|
||||||
|
replyId = command->second.alternativeReplyId;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
replyId = commandId;
|
||||||
}
|
}
|
||||||
|
DeviceReplyIter iter = deviceReplyMap.find(replyId);
|
||||||
|
if (iter != deviceReplyMap.end()) {
|
||||||
|
if (iter->second.delayCycles != 0) {
|
||||||
|
return iter->second.replyLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply,
|
ReturnValue_t DeviceHandlerBase::updateReplyMapEntry(DeviceCommandId_t deviceReply,
|
||||||
@ -651,7 +663,9 @@ void DeviceHandlerBase::doGetWrite() {
|
|||||||
|
|
||||||
// We need to distinguish here, because a raw command never expects a reply.
|
// We need to distinguish here, because a raw command never expects a reply.
|
||||||
//(Could be done in eRIRM, but then child implementations need to be careful.
|
//(Could be done in eRIRM, but then child implementations need to be careful.
|
||||||
result = enableReplyInReplyMap(cookieInfo.pendingCommand);
|
DeviceCommandMap::iterator command = cookieInfo.pendingCommand;
|
||||||
|
result = enableReplyInReplyMap(command, 1, command->second.useAlternativeReplyId,
|
||||||
|
command->second.alternativeReplyId);
|
||||||
} else {
|
} else {
|
||||||
// always generate a failure event, so that FDIR knows what's up
|
// always generate a failure event, so that FDIR knows what's up
|
||||||
triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first);
|
triggerEvent(DEVICE_SENDING_COMMAND_FAILED, result, cookieInfo.pendingCommand->first);
|
||||||
@ -824,7 +838,7 @@ void DeviceHandlerBase::handleReply(const uint8_t* receivedData, DeviceCommandId
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, uint8_t** data,
|
||||||
uint32_t* len) {
|
size_t* len) {
|
||||||
size_t lenTmp;
|
size_t lenTmp;
|
||||||
|
|
||||||
if (IPCStore == nullptr) {
|
if (IPCStore == nullptr) {
|
||||||
|
@ -478,7 +478,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @return - @c RETURN_OK when the command was successfully inserted,
|
* @return - @c RETURN_OK when the command was successfully inserted,
|
||||||
* - @c RETURN_FAILED else.
|
* - @c RETURN_FAILED else.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand);
|
ReturnValue_t insertInCommandMap(DeviceCommandId_t deviceCommand,
|
||||||
|
bool useAlternativeReply = false,
|
||||||
|
DeviceCommandId_t alternativeReplyId = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables a periodic reply for a given command. It sets to delay cycles to the specified
|
* Enables a periodic reply for a given command. It sets to delay cycles to the specified
|
||||||
@ -673,7 +675,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
//! Pointer to the raw packet that will be sent.
|
//! Pointer to the raw packet that will be sent.
|
||||||
uint8_t *rawPacket = nullptr;
|
uint8_t *rawPacket = nullptr;
|
||||||
//! Size of the #rawPacket.
|
//! Size of the #rawPacket.
|
||||||
uint32_t rawPacketLen = 0;
|
size_t rawPacketLen = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mode the device handler is currently in.
|
* The mode the device handler is currently in.
|
||||||
@ -751,6 +753,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
//! if this is != NO_COMMANDER, DHB was commanded externally and shall
|
//! if this is != NO_COMMANDER, DHB was commanded externally and shall
|
||||||
//! report everything to commander.
|
//! report everything to commander.
|
||||||
MessageQueueId_t sendReplyTo;
|
MessageQueueId_t sendReplyTo;
|
||||||
|
bool useAlternativeReplyId;
|
||||||
|
DeviceCommandId_t alternativeReplyId;
|
||||||
};
|
};
|
||||||
using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo>;
|
using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo>;
|
||||||
/**
|
/**
|
||||||
@ -1250,7 +1254,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* - @c RETURN_FAILED IPCStore is nullptr
|
* - @c RETURN_FAILED IPCStore is nullptr
|
||||||
* - the return value from the IPCStore if it was not @c RETURN_OK
|
* - the return value from the IPCStore if it was not @c RETURN_OK
|
||||||
*/
|
*/
|
||||||
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, uint32_t *len);
|
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, size_t *len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else!
|
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW, nothing else!
|
||||||
|
@ -7,8 +7,14 @@
|
|||||||
// could be moved to more suitable location
|
// could be moved to more suitable location
|
||||||
#include <events/subsystemIdRanges.h>
|
#include <events/subsystemIdRanges.h>
|
||||||
|
|
||||||
typedef uint16_t EventId_t;
|
using EventId_t = uint16_t;
|
||||||
typedef uint8_t EventSeverity_t;
|
using EventSeverity_t = uint8_t;
|
||||||
|
using UniqueEventId_t = uint8_t;
|
||||||
|
|
||||||
|
namespace severity {
|
||||||
|
enum Severity : EventSeverity_t { INFO = 1, LOW = 2, MEDIUM = 3, HIGH = 4 };
|
||||||
|
|
||||||
|
} // namespace severity
|
||||||
|
|
||||||
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
|
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
|
||||||
|
|
||||||
@ -20,18 +26,11 @@ constexpr EventId_t getEventId(Event event) { return (event & 0xFFFF); }
|
|||||||
|
|
||||||
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
|
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
|
||||||
|
|
||||||
constexpr Event makeEvent(uint8_t subsystemId, uint8_t uniqueEventId,
|
constexpr Event makeEvent(uint8_t subsystemId, UniqueEventId_t uniqueEventId,
|
||||||
EventSeverity_t eventSeverity) {
|
EventSeverity_t eventSeverity) {
|
||||||
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
|
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace event
|
} // namespace event
|
||||||
|
|
||||||
namespace severity {
|
|
||||||
static constexpr EventSeverity_t INFO = 1;
|
|
||||||
static constexpr EventSeverity_t LOW = 2;
|
|
||||||
static constexpr EventSeverity_t MEDIUM = 3;
|
|
||||||
static constexpr EventSeverity_t HIGH = 4;
|
|
||||||
} // namespace severity
|
|
||||||
|
|
||||||
#endif /* EVENTOBJECT_EVENT_H_ */
|
#endif /* EVENTOBJECT_EVENT_H_ */
|
||||||
|
@ -28,7 +28,7 @@ const uint16_t CRC::crc16ccitt_table[256] = {
|
|||||||
|
|
||||||
// CRC implementation
|
// CRC implementation
|
||||||
uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc) {
|
uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t startingCrc) {
|
||||||
uint8_t *data = (uint8_t *)input;
|
const uint8_t *data = static_cast<const uint8_t *>(input);
|
||||||
unsigned int tbl_idx;
|
unsigned int tbl_idx;
|
||||||
|
|
||||||
while (length--) {
|
while (length--) {
|
||||||
@ -39,88 +39,4 @@ uint16_t CRC::crc16ccitt(uint8_t const input[], uint32_t length, uint16_t starti
|
|||||||
}
|
}
|
||||||
return startingCrc & 0xffff;
|
return startingCrc & 0xffff;
|
||||||
|
|
||||||
// The part below is not used!
|
|
||||||
// bool temr[16];
|
|
||||||
// bool xor_out[16];
|
|
||||||
// bool r[16];
|
|
||||||
// bool d[8];
|
|
||||||
// uint16_t crc_value = 0;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// for (int i=0; i<16 ;i++) {
|
|
||||||
// temr[i] = false;
|
|
||||||
// xor_out[i] = false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// for (int i=0; i<16 ;i++)
|
|
||||||
// r[i] = true; // initialize with 0xFFFF
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// for (int j=0; j<length ;j++)
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// for (int i=0; i<8 ;i++)
|
|
||||||
// if ((input[j] & 1<<i) == 1<<i)
|
|
||||||
// d[7-i]=true; // reverse input data
|
|
||||||
// else
|
|
||||||
// d[7-i]=false; // reverse input data
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// temr[0] = d[4] ^ d[0];
|
|
||||||
// temr[1] = d[5] ^ d[1];
|
|
||||||
// temr[2] = d[6] ^ d[2];
|
|
||||||
// temr[3] = d[7] ^ d[3];
|
|
||||||
// temr[4] = r[12] ^ r[8];
|
|
||||||
// temr[5] = r[13] ^ r[9];
|
|
||||||
// temr[6] = r[14] ^ r[10];
|
|
||||||
// temr[7] = r[15] ^ r[11];
|
|
||||||
// temr[8] = d[4] ^ r[12];
|
|
||||||
// temr[9] = d[5] ^ r[13];
|
|
||||||
// temr[10] = d[6] ^ r[14];
|
|
||||||
// temr[11] = d[7] ^ r[15];
|
|
||||||
// temr[12] = temr[0] ^ temr[4];
|
|
||||||
// temr[13] = temr[1] ^ temr[5];
|
|
||||||
// temr[14] = temr[2] ^ temr[6];
|
|
||||||
// temr[15] = temr[3] ^ temr[7];
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// xor_out[0] = temr[12];
|
|
||||||
// xor_out[1] = temr[13];
|
|
||||||
// xor_out[2] = temr[14];
|
|
||||||
// xor_out[3] = temr[15];
|
|
||||||
// xor_out[4] = temr[8];
|
|
||||||
// xor_out[5] = temr[9] ^ temr[12];
|
|
||||||
// xor_out[6] = temr[10] ^ temr[13];
|
|
||||||
// xor_out[7] = temr[11] ^ temr[14];
|
|
||||||
// xor_out[8] = temr[15] ^ r[0];
|
|
||||||
// xor_out[9] = temr[8] ^ r[1];
|
|
||||||
// xor_out[10] = temr[9] ^ r[2];
|
|
||||||
// xor_out[11] = temr[10] ^ r[3];
|
|
||||||
// xor_out[12] = temr[11] ^ temr[12] ^ r[4];
|
|
||||||
// xor_out[13] = temr[13] ^ r[5];
|
|
||||||
// xor_out[14] = temr[14] ^ r[6];
|
|
||||||
// xor_out[15] = temr[15] ^ r[7];
|
|
||||||
//
|
|
||||||
// for (int i=0; i<16 ;i++)
|
|
||||||
// {
|
|
||||||
// r[i]= xor_out[i] ;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// for (int i=0; i<16 ;i++)
|
|
||||||
// {
|
|
||||||
// if (xor_out[i] == true)
|
|
||||||
// crc_value = crc_value + pow(2,(15 -i)); // reverse CrC result before Final
|
|
||||||
//XOR
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// crc_value = 0;// for debug mode
|
|
||||||
// return (crc_value);
|
|
||||||
|
|
||||||
} /* Calculate_CRC() */
|
} /* Calculate_CRC() */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, size_t maxCharPerL
|
|||||||
currentPos += snprintf(printBuffer + currentPos, 6, "%02x", data[i]);
|
currentPos += snprintf(printBuffer + currentPos, 6, "%02x", data[i]);
|
||||||
if (i < size - 1) {
|
if (i < size - 1) {
|
||||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
currentPos += sprintf(printBuffer + currentPos, ",");
|
||||||
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
if ((i + 1) % maxCharPerLine == 0) {
|
||||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
currentPos += sprintf(printBuffer + currentPos, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,20 +98,21 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, size_t maxCharPerL
|
|||||||
}
|
}
|
||||||
std::cout << "]" << std::endl;
|
std::cout << "]" << std::endl;
|
||||||
#else
|
#else
|
||||||
// General format: 32, 243, -12 so it is number of chars times 5
|
// General format: 32,243,-12 so it is number of chars times 4
|
||||||
// plus line break plus small safety margin.
|
// plus line break plus small safety margin.
|
||||||
char printBuffer[(size + 1) * 5 + 1] = {};
|
uint16_t expectedLines = ceil((double)size / maxCharPerLine);
|
||||||
|
char printBuffer[size * 4 + 1 + expectedLines] = {};
|
||||||
size_t currentPos = 0;
|
size_t currentPos = 0;
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
// To avoid buffer overflows.
|
// To avoid buffer overflows.
|
||||||
if (sizeof(printBuffer) - currentPos <= 5) {
|
if (sizeof(printBuffer) - currentPos <= 4) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPos += snprintf(printBuffer + currentPos, 3, "%d", data[i]);
|
currentPos += snprintf(printBuffer + currentPos, 4, "%d", data[i]);
|
||||||
if (i < size - 1) {
|
if (i < size - 1) {
|
||||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
currentPos += sprintf(printBuffer + currentPos, ",");
|
||||||
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
if ((i + 1) % maxCharPerLine == 0) {
|
||||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
currentPos += sprintf(printBuffer + currentPos, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,9 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
|||||||
internalErrorDataset.storeHits.value += newStoreHits;
|
internalErrorDataset.storeHits.value += newStoreHits;
|
||||||
internalErrorDataset.tmHits.value += newTmHits;
|
internalErrorDataset.tmHits.value += newTmHits;
|
||||||
internalErrorDataset.setValidity(true, true);
|
internalErrorDataset.setValidity(true, true);
|
||||||
|
if ((newQueueHits != 0) or (newStoreHits != 0) or (newTmHits != 0)) {
|
||||||
|
internalErrorDataset.setChanged(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,14 +80,6 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getQueueHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = queueHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementQueueHits() {
|
void InternalErrorReporter::incrementQueueHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
queueHits++;
|
queueHits++;
|
||||||
@ -100,14 +95,6 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getTmHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = tmHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementTmHits() {
|
void InternalErrorReporter::incrementTmHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
tmHits++;
|
tmHits++;
|
||||||
@ -125,14 +112,6 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InternalErrorReporter::getStoreHits() {
|
|
||||||
uint32_t value;
|
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
|
||||||
value = storeHits;
|
|
||||||
mutex->unlockMutex();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InternalErrorReporter::incrementStoreHits() {
|
void InternalErrorReporter::incrementStoreHits() {
|
||||||
mutex->lockMutex(timeoutType, timeoutMs);
|
mutex->lockMutex(timeoutType, timeoutMs);
|
||||||
storeHits++;
|
storeHits++;
|
||||||
|
@ -46,11 +46,11 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
virtual void queueMessageNotSent();
|
virtual void queueMessageNotSent() override;
|
||||||
|
|
||||||
virtual void lostTm();
|
virtual void lostTm() override;
|
||||||
|
|
||||||
virtual void storeFull();
|
virtual void storeFull() override;
|
||||||
|
|
||||||
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
virtual void setTaskIF(PeriodicTaskIF* task) override;
|
||||||
|
|
||||||
@ -74,15 +74,12 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
uint32_t storeHits = 0;
|
uint32_t storeHits = 0;
|
||||||
|
|
||||||
uint32_t getAndResetQueueHits();
|
uint32_t getAndResetQueueHits();
|
||||||
uint32_t getQueueHits();
|
|
||||||
void incrementQueueHits();
|
void incrementQueueHits();
|
||||||
|
|
||||||
uint32_t getAndResetTmHits();
|
uint32_t getAndResetTmHits();
|
||||||
uint32_t getTmHits();
|
|
||||||
void incrementTmHits();
|
void incrementTmHits();
|
||||||
|
|
||||||
uint32_t getAndResetStoreHits();
|
uint32_t getAndResetStoreHits();
|
||||||
uint32_t getStoreHits();
|
|
||||||
void incrementStoreHits();
|
void incrementStoreHits();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,22 +1,34 @@
|
|||||||
#ifndef INTERNALERRORREPORTERIF_H_
|
#ifndef INTERNALERRORREPORTERIF_H_
|
||||||
#define INTERNALERRORREPORTERIF_H_
|
#define INTERNALERRORREPORTERIF_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interface which is used to report internal errors like full message queues or stores.
|
||||||
|
* @details
|
||||||
|
* This interface smust be used for the InteralErrorReporter object.
|
||||||
|
* It should be used to indicate that there was a Problem with Queues or Stores.
|
||||||
|
*
|
||||||
|
* It can be used to report missing Telemetry which could not be sent due to a internal problem.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class InternalErrorReporterIF {
|
class InternalErrorReporterIF {
|
||||||
public:
|
public:
|
||||||
virtual ~InternalErrorReporterIF() {}
|
virtual ~InternalErrorReporterIF() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if a message queue could not be sent.
|
||||||
|
* @details OSAL Implementations should call this function to indicate that
|
||||||
|
* a message was lost.
|
||||||
|
*
|
||||||
|
* Implementations are required to be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void queueMessageNotSent() = 0;
|
virtual void queueMessageNotSent() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if Telemetry could not be sent
|
||||||
|
* @details Implementations must be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void lostTm() = 0;
|
virtual void lostTm() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread safe
|
* @brief Function to be called if a onboard storage is full
|
||||||
|
* @details Implementations must be Thread safe
|
||||||
*/
|
*/
|
||||||
virtual void storeFull() = 0;
|
virtual void storeFull() = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
PRIVATE
|
|
||||||
CommandMessage.cpp
|
CommandMessage.cpp
|
||||||
CommandMessageCleaner.cpp
|
CommandMessageCleaner.cpp
|
||||||
MessageQueueMessage.cpp
|
MessageQueueMessage.cpp
|
||||||
|
MessageQueueBase.cpp
|
||||||
)
|
)
|
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
54
src/fsfw/ipc/MessageQueueBase.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "MessageQueueBase.h"
|
||||||
|
|
||||||
|
MessageQueueBase::MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* args)
|
||||||
|
: id(id) {
|
||||||
|
this->defaultDest = defaultDest;
|
||||||
|
if (args != nullptr) {
|
||||||
|
this->args = *args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueBase::~MessageQueueBase() {}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendToDefault(MessageQueueMessageIF* message) {
|
||||||
|
return sendToDefaultFrom(message, this->getId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::reply(MessageQueueMessageIF* message) {
|
||||||
|
if (this->last != MessageQueueIF::NO_QUEUE) {
|
||||||
|
return sendMessageFrom(this->last, message, this->getId());
|
||||||
|
} else {
|
||||||
|
return NO_REPLY_PARTNER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::receiveMessage(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t* receivedFrom) {
|
||||||
|
ReturnValue_t status = this->receiveMessage(message);
|
||||||
|
*receivedFrom = this->last;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getLastPartner() const { return last; }
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getId() const { return id; }
|
||||||
|
|
||||||
|
MqArgs& MessageQueueBase::getMqArgs() { return args; }
|
||||||
|
|
||||||
|
void MessageQueueBase::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||||
|
this->defaultDest = defaultDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueueId_t MessageQueueBase::getDefaultDestination() const { return defaultDest; }
|
||||||
|
|
||||||
|
bool MessageQueueBase::isDefaultDestinationSet() const { return (defaultDest != NO_QUEUE); }
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
bool ignoreFault) {
|
||||||
|
return sendMessageFrom(sendTo, message, this->getId(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t MessageQueueBase::sendToDefaultFrom(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
|
return sendMessageFrom(defaultDest, message, sentFrom, ignoreFault);
|
||||||
|
}
|
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
40
src/fsfw/ipc/MessageQueueBase.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||||
|
#define FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/ipc/definitions.h>
|
||||||
|
|
||||||
|
class MessageQueueBase : public MessageQueueIF {
|
||||||
|
public:
|
||||||
|
MessageQueueBase(MessageQueueId_t id, MessageQueueId_t defaultDest, MqArgs* mqArgs);
|
||||||
|
virtual ~MessageQueueBase();
|
||||||
|
|
||||||
|
// Default implementations for MessageQueueIF where possible
|
||||||
|
virtual MessageQueueId_t getLastPartner() const override;
|
||||||
|
virtual MessageQueueId_t getId() const override;
|
||||||
|
virtual MqArgs& getMqArgs() override;
|
||||||
|
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
||||||
|
virtual MessageQueueId_t getDefaultDestination() const override;
|
||||||
|
virtual bool isDefaultDestinationSet() const override;
|
||||||
|
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
bool ignoreFault) override;
|
||||||
|
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
||||||
|
virtual ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t* receivedFrom) override;
|
||||||
|
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
|
||||||
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
|
// OSAL specific, forward the abstract function
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessageIF* message) = 0;
|
||||||
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
|
MessageQueueId_t sentFrom, bool ignoreFault = false) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MessageQueueId_t id = MessageQueueIF::NO_QUEUE;
|
||||||
|
MessageQueueId_t last = MessageQueueIF::NO_QUEUE;
|
||||||
|
MessageQueueId_t defaultDest = MessageQueueIF::NO_QUEUE;
|
||||||
|
MqArgs args = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_SRC_FSFW_IPC_MESSAGEQUEUEBASE_H_ */
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
|
#ifndef FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||||
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
#define FSFW_IPC_MESSAGEQUEUEIF_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/definitions.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||||
@ -44,8 +46,8 @@ class MessageQueueIF {
|
|||||||
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
|
virtual ReturnValue_t reply(MessageQueueMessageIF* message) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function reads available messages from the message queue
|
* @brief This function reads available messages from the message queue and returns the
|
||||||
* and returns the sender.
|
* sender.
|
||||||
* @details
|
* @details
|
||||||
* It works identically to the other receiveMessage call, but in addition
|
* It works identically to the other receiveMessage call, but in addition
|
||||||
* returns the sender's queue id.
|
* returns the sender's queue id.
|
||||||
@ -78,19 +80,16 @@ class MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t flush(uint32_t* count) = 0;
|
virtual ReturnValue_t flush(uint32_t* count) = 0;
|
||||||
/**
|
/**
|
||||||
* @brief This method returns the message queue
|
* @brief This method returns the message queue ID of the last communication partner.
|
||||||
* id of the last communication partner.
|
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getLastPartner() const = 0;
|
virtual MessageQueueId_t getLastPartner() const = 0;
|
||||||
/**
|
/**
|
||||||
* @brief This method returns the message queue
|
* @brief This method returns the message queue ID of this class's message queue.
|
||||||
* id of this class's message queue.
|
|
||||||
*/
|
*/
|
||||||
virtual MessageQueueId_t getId() const = 0;
|
virtual MessageQueueId_t getId() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief With the sendMessage call, a queue message
|
* @brief With the sendMessage call, a queue message is sent to a receiving queue.
|
||||||
* is sent to a receiving queue.
|
|
||||||
* @details
|
* @details
|
||||||
* This method takes the message provided, adds the sentFrom information
|
* This method takes the message provided, adds the sentFrom information
|
||||||
* and passes it on to the destination provided with an operating system
|
* and passes it on to the destination provided with an operating system
|
||||||
@ -129,8 +128,7 @@ class MessageQueueIF {
|
|||||||
bool ignoreFault = false) = 0;
|
bool ignoreFault = false) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The sendToDefaultFrom method sends a queue message
|
* @brief The sendToDefaultFrom method sends a queue message to the default destination.
|
||||||
* to the default destination.
|
|
||||||
* @details
|
* @details
|
||||||
* In all other aspects, it works identical to the sendMessage method.
|
* In all other aspects, it works identical to the sendMessage method.
|
||||||
* @param message
|
* @param message
|
||||||
@ -164,6 +162,8 @@ class MessageQueueIF {
|
|||||||
virtual MessageQueueId_t getDefaultDestination() const = 0;
|
virtual MessageQueueId_t getDefaultDestination() const = 0;
|
||||||
|
|
||||||
virtual bool isDefaultDestinationSet() const = 0;
|
virtual bool isDefaultDestinationSet() const = 0;
|
||||||
|
|
||||||
|
virtual MqArgs& getMqArgs() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
|
#endif /* FSFW_IPC_MESSAGEQUEUEIF_H_ */
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "MessageQueueIF.h"
|
#include "MessageQueueIF.h"
|
||||||
#include "MessageQueueMessage.h"
|
#include "MessageQueueMessage.h"
|
||||||
|
#include "definitions.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates message queues.
|
* Creates message queues.
|
||||||
@ -22,7 +23,8 @@ class QueueFactory {
|
|||||||
static QueueFactory* instance();
|
static QueueFactory* instance();
|
||||||
|
|
||||||
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
|
MessageQueueIF* createMessageQueue(uint32_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
void deleteMessageQueue(MessageQueueIF* queue);
|
void deleteMessageQueue(MessageQueueIF* queue);
|
||||||
|
|
||||||
|
14
src/fsfw/ipc/definitions.h
Normal file
14
src/fsfw/ipc/definitions.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||||
|
#define FSFW_SRC_FSFW_IPC_DEFINITIONS_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||||
|
|
||||||
|
struct MqArgs {
|
||||||
|
MqArgs(){};
|
||||||
|
MqArgs(object_id_t objectId, void* args = nullptr) : objectId(objectId), args(args) {}
|
||||||
|
object_id_t objectId = objects::NO_OBJECT;
|
||||||
|
void* args = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_SRC_FSFW_IPC_DEFINITIONS_H_ */
|
@ -14,30 +14,30 @@ class ModeMessage {
|
|||||||
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
||||||
static const Command_t CMD_MODE_COMMAND =
|
static const Command_t CMD_MODE_COMMAND =
|
||||||
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||||
//!REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||||
//!as this will break the subsystem mode machine!!
|
//! as this will break the subsystem mode machine!!
|
||||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
|
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
|
||||||
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
|
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
|
||||||
//!are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||||
//!replies, as this will break the subsystem mode machine!!
|
//! replies, as this will break the subsystem mode machine!!
|
||||||
static const Command_t REPLY_MODE_REPLY =
|
static const Command_t REPLY_MODE_REPLY =
|
||||||
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||||
static const Command_t REPLY_MODE_INFO =
|
static const Command_t REPLY_MODE_INFO =
|
||||||
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
|
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
|
||||||
//!inform their container of a changed mode)
|
//! inform their container of a changed mode)
|
||||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
|
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
|
||||||
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||||
static const Command_t REPLY_WRONG_MODE_REPLY =
|
static const Command_t REPLY_WRONG_MODE_REPLY =
|
||||||
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||||
//!and a transition started but was aborted; the parameters contain
|
//! and a transition started but was aborted; the parameters contain
|
||||||
//!the mode that was reached
|
//! the mode that was reached
|
||||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
|
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
|
||||||
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
|
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
|
||||||
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
|
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
|
||||||
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
|
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
|
||||||
//!every child. This command does NOT have a reply.
|
//! every child. This command does NOT have a reply.
|
||||||
|
|
||||||
static Mode_t getMode(const CommandMessage* message);
|
static Mode_t getMode(const CommandMessage* message);
|
||||||
static Submode_t getSubmode(const CommandMessage* message);
|
static Submode_t getSubmode(const CommandMessage* message);
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
// TODO sanitize input?
|
// TODO sanitize input?
|
||||||
// TODO much of this code can be reused for tick-only systems
|
// TODO much of this code can be reused for tick-only systems
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = nullptr;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
#include "fsfw/osal/freertos/QueueMapManager.h"
|
#include "fsfw/osal/freertos/QueueMapManager.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: maxMessageSize(maxMessageSize) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
maxMessageSize(maxMessageSize) {
|
||||||
handle = xQueueCreate(messageDepth, maxMessageSize);
|
handle = xQueueCreate(messageDepth, maxMessageSize);
|
||||||
if (handle == nullptr) {
|
if (handle == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -15,10 +16,10 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
|||||||
#else
|
#else
|
||||||
sif::printError("MessageQueue::MessageQueue: Creation failed\n");
|
sif::printError("MessageQueue::MessageQueue: Creation failed\n");
|
||||||
sif::printError("Specified Message Depth: %d\n", messageDepth);
|
sif::printError("Specified Message Depth: %d\n", messageDepth);
|
||||||
sif::printError("Specified MAximum Message Size: %d\n", maxMessageSize);
|
sif::printError("Specified Maximum Message Size: %d\n", maxMessageSize);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
QueueMapManager::instance()->addMessageQueue(handle, &queueId);
|
QueueMapManager::instance()->addMessageQueue(handle, &id);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueue::~MessageQueue() {
|
MessageQueue::~MessageQueue() {
|
||||||
@ -29,28 +30,6 @@ MessageQueue::~MessageQueue() {
|
|||||||
|
|
||||||
void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; }
|
void MessageQueue::switchSystemContext(CallContext callContext) { this->callContext = callContext; }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault, callContext);
|
||||||
@ -72,27 +51,16 @@ ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
if (status == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0);
|
BaseType_t result = xQueueReceive(handle, reinterpret_cast<void*>(message->getBuffer()), 0);
|
||||||
if (result == pdPASS) {
|
if (result == pdPASS) {
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
} else {
|
} else {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
// TODO FreeRTOS does not support flushing partially
|
// TODO FreeRTOS does not support flushing partially
|
||||||
// Is always successful
|
// Is always successful
|
||||||
@ -100,17 +68,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return queueId; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
defaultDestinationSet = true;
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
|
|
||||||
|
|
||||||
// static core function to send messages.
|
// static core function to send messages.
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
MessageQueueMessageIF* message,
|
MessageQueueMessageIF* message,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_FREERTOS_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "TaskManagement.h"
|
#include "TaskManagement.h"
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessageIF.h"
|
#include "fsfw/ipc/MessageQueueMessageIF.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +35,7 @@
|
|||||||
* @ingroup osal
|
* @ingroup osal
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -53,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t messageDepth = 3,
|
MessageQueue(size_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
/** Copying message queues forbidden */
|
/** Copying message queues forbidden */
|
||||||
MessageQueue(const MessageQueue&) = delete;
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
@ -73,40 +77,15 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
void switchSystemContext(CallContext callContext);
|
void switchSystemContext(CallContext callContext);
|
||||||
|
|
||||||
/** MessageQueueIF implementation */
|
QueueHandle_t getNativeQueueHandle();
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false) override;
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) override;
|
|
||||||
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
|
|
||||||
ReturnValue_t flush(uint32_t* count) override;
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
|
|
||||||
MessageQueueId_t getLastPartner() const override;
|
|
||||||
|
|
||||||
MessageQueueId_t getId() const override;
|
|
||||||
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
|
||||||
|
|
||||||
MessageQueueId_t getDefaultDestination() const override;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const override;
|
|
||||||
|
|
||||||
QueueHandle_t getNativeQueueHandle();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Implementation to be called from any send Call within
|
* @brief Implementation to be called from any send Call within
|
||||||
@ -136,12 +115,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool defaultDestinationSet = false;
|
|
||||||
QueueHandle_t handle;
|
QueueHandle_t handle;
|
||||||
MessageQueueId_t queueId = MessageQueueIF::NO_QUEUE;
|
|
||||||
|
|
||||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
|
||||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
|
||||||
const size_t maxMessageSize;
|
const size_t maxMessageSize;
|
||||||
//! Stores the current system context
|
//! Stores the current system context
|
||||||
CallContext callContext = CallContext::TASK;
|
CallContext callContext = CallContext::TASK;
|
||||||
|
@ -97,7 +97,11 @@ void PeriodicTask::taskFunctionality() {
|
|||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
if (newObject == nullptr) {
|
return addComponent(newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||||
|
if (object == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||||
"it implement ExecutableObjectIF"
|
"it implement ExecutableObjectIF"
|
||||||
@ -105,8 +109,8 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
|||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
objectList.push_back(newObject);
|
objectList.push_back(object);
|
||||||
newObject->setTaskIF(this);
|
object->setTaskIF(this);
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,16 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t addComponent(object_id_t object) override;
|
ReturnValue_t addComponent(object_id_t object) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an object to the list of objects to be executed.
|
||||||
|
* The objects are executed in the order added.
|
||||||
|
* @param object Id of the object to add.
|
||||||
|
* @return
|
||||||
|
* -@c RETURN_OK on success
|
||||||
|
* -@c RETURN_FAILED if the object could not be added.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
@ -22,8 +22,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
@ -11,9 +12,6 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = NULL;
|
|
||||||
|
|
||||||
using SystemClock = std::chrono::system_clock;
|
using SystemClock = std::chrono::system_clock;
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
@ -127,6 +125,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|||||||
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||||
auto fraction = now - seconds;
|
auto fraction = now - seconds;
|
||||||
time_t tt = SystemClock::to_time_t(now);
|
time_t tt = SystemClock::to_time_t(now);
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
struct tm* timeInfo;
|
struct tm* timeInfo;
|
||||||
timeInfo = gmtime(&tt);
|
timeInfo = gmtime(&tt);
|
||||||
time->year = timeInfo->tm_year + 1900;
|
time->year = timeInfo->tm_year + 1900;
|
||||||
@ -150,17 +155,14 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
|
|||||||
time_tm.tm_hour = from->hour;
|
time_tm.tm_hour = from->hour;
|
||||||
time_tm.tm_min = from->minute;
|
time_tm.tm_min = from->minute;
|
||||||
time_tm.tm_sec = from->second;
|
time_tm.tm_sec = from->second;
|
||||||
|
time_tm.tm_isdst = 0;
|
||||||
|
|
||||||
time_t seconds = mktime(&time_tm);
|
time_t seconds = timegm(&time_tm);
|
||||||
|
|
||||||
to->tv_sec = seconds;
|
to->tv_sec = seconds;
|
||||||
to->tv_usec = from->usecond;
|
to->tv_usec = from->usecond;
|
||||||
// Fails in 2038..
|
// Fails in 2038..
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
#include "fsfw/osal/host/QueueMapManager.h"
|
#include "fsfw/osal/host/QueueMapManager.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: messageSize(maxMessageSize), messageDepth(messageDepth) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
messageSize(maxMessageSize),
|
||||||
|
messageDepth(messageDepth) {
|
||||||
queueLock = MutexFactory::instance()->createMutex();
|
queueLock = MutexFactory::instance()->createMutex();
|
||||||
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
|
auto result = QueueMapManager::instance()->addMessageQueue(this, &id);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
sif::error << "MessageQueue::MessageQueue: Could not be created" << std::endl;
|
||||||
@ -23,42 +25,11 @@ MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize)
|
|||||||
|
|
||||||
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
|
MessageQueue::~MessageQueue() { MutexFactory::instance()->deleteMutex(queueLock); }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != MessageQueueIF::NO_QUEUE) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return MessageQueueIF::NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
if (status == HasReturnvaluesIF::RETURN_OK) {
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
if (messageQueue.empty()) {
|
if (messageQueue.empty()) {
|
||||||
return MessageQueueIF::EMPTY;
|
return MessageQueueIF::EMPTY;
|
||||||
@ -68,12 +39,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
message->getBuffer());
|
message->getBuffer());
|
||||||
messageQueue.pop();
|
messageQueue.pop();
|
||||||
// The last partner is the first uint32_t field in the message
|
// The last partner is the first uint32_t field in the message
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
*count = messageQueue.size();
|
*count = messageQueue.size();
|
||||||
// Clears the queue.
|
// Clears the queue.
|
||||||
@ -81,17 +50,6 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return mqId; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
defaultDestinationSet = true;
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return defaultDestinationSet; }
|
|
||||||
|
|
||||||
// static core function to send messages.
|
// static core function to send messages.
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
MessageQueueMessageIF* message,
|
MessageQueueMessageIF* message,
|
||||||
@ -125,6 +83,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
memcpy(targetQueue->messageQueue.back().data(), message->getBuffer(),
|
||||||
message->getMaximumMessageSize());
|
message->getMaximumMessageSize());
|
||||||
} else {
|
} else {
|
||||||
|
if (not ignoreFault) {
|
||||||
|
InternalErrorReporterIF* internalErrorReporter =
|
||||||
|
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
if (internalErrorReporter != nullptr) {
|
||||||
|
internalErrorReporter->queueMessageNotSent();
|
||||||
|
}
|
||||||
|
}
|
||||||
return MessageQueueIF::FULL;
|
return MessageQueueIF::FULL;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
|
#include "fsfw/ipc/MessageQueueBase.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
#include "fsfw/ipc/MutexIF.h"
|
#include "fsfw/ipc/MutexIF.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +35,7 @@
|
|||||||
* @ingroup osal
|
* @ingroup osal
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -54,7 +56,8 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t messageDepth = 3,
|
MessageQueue(size_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
/** Copying message queues forbidden */
|
/** Copying message queues forbidden */
|
||||||
MessageQueue(const MessageQueue&) = delete;
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
@ -67,121 +70,12 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
*/
|
*/
|
||||||
virtual ~MessageQueue();
|
virtual ~MessageQueue();
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender
|
|
||||||
* parent, but passes its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the
|
|
||||||
* destination message queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter
|
|
||||||
* is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the
|
|
||||||
* sendToDefault call of the MessageQueueSender parent class and adds its
|
|
||||||
* queue id as "sentFrom" information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using
|
|
||||||
* the stored lastPartner information as destination. If there was no
|
|
||||||
* message received yet (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief With the sendMessage call, a queue message is sent to a
|
|
||||||
* receiving queue.
|
|
||||||
* @details
|
|
||||||
* This method takes the message provided, adds the sentFrom information and
|
|
||||||
* passes it on to the destination provided with an operating system call.
|
|
||||||
* The OS's return value is returned.
|
|
||||||
* @param sendTo This parameter specifies the message queue id to send
|
|
||||||
* the message to.
|
|
||||||
* @param message This is a pointer to a previously created message,
|
|
||||||
* which is sent.
|
|
||||||
* @param sentFrom The sentFrom information can be set to inject the
|
|
||||||
* sender's queue id into the message. This variable is set to zero by
|
|
||||||
* default.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter
|
|
||||||
* is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false) override;
|
bool ignoreFault = false) override;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The sendToDefault method sends a queue message to the default
|
|
||||||
* destination.
|
|
||||||
* @details
|
|
||||||
* In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* @param message This is a pointer to a previously created message,
|
|
||||||
* which is sent.
|
|
||||||
* @param sentFrom The sentFrom information can be set to inject the
|
|
||||||
* sender's queue id into the message. This variable is set to zero by
|
|
||||||
* default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue
|
|
||||||
* and returns the sender.
|
|
||||||
* @details
|
|
||||||
* It works identically to the other receiveMessage call, but in addition
|
|
||||||
* returns the sender's queue id.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details
|
|
||||||
* If data is available it is stored in the passed message pointer.
|
|
||||||
* The message's original content is overwritten and the sendFrom
|
|
||||||
* information is stored in the lastPartner attribute. Else, the lastPartner
|
|
||||||
* information remains untouched, the message's content is cleared and the
|
|
||||||
* function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count) override;
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last
|
|
||||||
* communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const override;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's
|
|
||||||
* message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
|
|
||||||
/**
|
|
||||||
* @brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const override;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const override;
|
|
||||||
|
|
||||||
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
|
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType, dur_millis_t lockTimeout);
|
||||||
ReturnValue_t unlockQueue();
|
ReturnValue_t unlockQueue();
|
||||||
@ -211,23 +105,14 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false);
|
bool ignoreFault = false);
|
||||||
|
|
||||||
// static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::queue<std::vector<uint8_t>> messageQueue;
|
std::queue<std::vector<uint8_t>> messageQueue;
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned.
|
|
||||||
* If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t mqId = MessageQueueIF::NO_QUEUE;
|
|
||||||
size_t messageSize = 0;
|
size_t messageSize = 0;
|
||||||
size_t messageDepth = 0;
|
size_t messageDepth = 0;
|
||||||
|
|
||||||
MutexIF* queueLock;
|
MutexIF* queueLock;
|
||||||
|
|
||||||
bool defaultDestinationSet = false;
|
|
||||||
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t defaultDestination = MessageQueueIF::NO_QUEUE;
|
||||||
MessageQueueId_t lastPartner = MessageQueueIF::NO_QUEUE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */
|
||||||
|
@ -102,11 +102,15 @@ void PeriodicTask::taskFunctionality() {
|
|||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
if (newObject == nullptr) {
|
return addComponent(newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||||
|
if (object == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
newObject->setTaskIF(this);
|
object->setTaskIF(this);
|
||||||
objectList.push_back(newObject);
|
objectList.push_back(object);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,16 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t addComponent(object_id_t object);
|
ReturnValue_t addComponent(object_id_t object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an object to the list of objects to be executed.
|
||||||
|
* The objects are executed in the order added.
|
||||||
|
* @param object pointer to the object to add.
|
||||||
|
* @return
|
||||||
|
* -@c RETURN_OK on success
|
||||||
|
* -@c RETURN_FAILED if the object could not be added.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object);
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
uint32_t getPeriodMs() const;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
ReturnValue_t sleepFor(uint32_t ms);
|
||||||
|
@ -27,12 +27,13 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
|
MqArgs* args) {
|
||||||
// A thread-safe queue can be implemented by using a combination
|
// A thread-safe queue can be implemented by using a combination
|
||||||
// of std::queue and std::mutex. This uses dynamic memory allocation
|
// of std::queue and std::mutex. This uses dynamic memory allocation
|
||||||
// which could be alleviated by using a custom allocator, external library
|
// which could be alleviated by using a custom allocator, external library
|
||||||
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
|
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "fsfw/osal/linux/BinarySemaphore.h"
|
#include "fsfw/osal/linux/BinarySemaphore.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -8,11 +8,9 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = NULL;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
uint32_t ticks = sysconf(_SC_CLK_TCK);
|
||||||
return ticks;
|
return ticks;
|
||||||
@ -117,7 +115,13 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|||||||
// TODO errno
|
// TODO errno
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
struct tm* timeInfo;
|
struct tm* timeInfo;
|
||||||
timeInfo = gmtime(&timeUnix.tv_sec);
|
timeInfo = gmtime(&timeUnix.tv_sec);
|
||||||
time->year = timeInfo->tm_year + 1900;
|
time->year = timeInfo->tm_year + 1900;
|
||||||
@ -140,8 +144,9 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval*
|
|||||||
fromTm.tm_hour = from->hour;
|
fromTm.tm_hour = from->hour;
|
||||||
fromTm.tm_min = from->minute;
|
fromTm.tm_min = from->minute;
|
||||||
fromTm.tm_sec = from->second;
|
fromTm.tm_sec = from->second;
|
||||||
|
fromTm.tm_isdst = 0;
|
||||||
|
|
||||||
to->tv_sec = mktime(&fromTm);
|
to->tv_sec = timegm(&fromTm);
|
||||||
to->tv_usec = from->usecond;
|
to->tv_usec = from->usecond;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,10 @@
|
|||||||
#include "fsfw/osal/linux/unixUtility.h"
|
#include "fsfw/osal/linux/unixUtility.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize)
|
MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* args)
|
||||||
: id(MessageQueueIF::NO_QUEUE),
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
lastPartner(MessageQueueIF::NO_QUEUE),
|
|
||||||
defaultDestination(MessageQueueIF::NO_QUEUE),
|
|
||||||
maxMessageSize(maxMessageSize) {
|
maxMessageSize(maxMessageSize) {
|
||||||
mq_attr attributes;
|
mq_attr attributes;
|
||||||
this->id = 0;
|
|
||||||
// Set attributes
|
// Set attributes
|
||||||
attributes.mq_curmsgs = 0;
|
attributes.mq_curmsgs = 0;
|
||||||
attributes.mq_maxmsg = messageDepth;
|
attributes.mq_maxmsg = messageDepth;
|
||||||
@ -50,30 +47,6 @@ MessageQueue::~MessageQueue() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != 0) {
|
|
||||||
return sendMessageFrom(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
if (message == nullptr) {
|
if (message == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
@ -96,7 +69,7 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
|
int status = mq_receive(id, reinterpret_cast<char*>(message->getBuffer()),
|
||||||
message->getMaximumMessageSize(), &messagePriority);
|
message->getMaximumMessageSize(), &messagePriority);
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
// Check size of incoming message.
|
// Check size of incoming message.
|
||||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
@ -164,8 +137,6 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
mq_attr attrib;
|
mq_attr attrib;
|
||||||
int status = mq_getattr(id, &attrib);
|
int status = mq_getattr(id, &attrib);
|
||||||
@ -212,26 +183,11 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return this->id; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
return sendMessageFromMessageQueue(sendTo, message, sentFrom, ignoreFault);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
|
|
||||||
|
|
||||||
uint16_t MessageQueue::queueCounter = 0;
|
uint16_t MessageQueue::queueCounter = 0;
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
||||||
@ -240,9 +196,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
bool ignoreFault) {
|
bool ignoreFault) {
|
||||||
if (message == nullptr) {
|
if (message == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr!" << std::endl;
|
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message is nullptr" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr!\n");
|
sif::printError("MessageQueue::sendMessageFromMessageQueue: Message is nullptr\n");
|
||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
@ -256,7 +212,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
|
|||||||
if (!ignoreFault) {
|
if (!ignoreFault) {
|
||||||
InternalErrorReporterIF* internalErrorReporter =
|
InternalErrorReporterIF* internalErrorReporter =
|
||||||
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
ObjectManager::instance()->get<InternalErrorReporterIF>(objects::INTERNAL_ERROR_REPORTER);
|
||||||
if (internalErrorReporter != NULL) {
|
if (internalErrorReporter != nullptr) {
|
||||||
internalErrorReporter->queueMessageNotSent();
|
internalErrorReporter->queueMessageNotSent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_LINUX_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
#include <mqueue.h>
|
#include <mqueue.h>
|
||||||
|
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
/**
|
/**
|
||||||
* @brief This class manages sending and receiving of message queue messages.
|
* @brief This class manages sending and receiving of message queue messages.
|
||||||
*
|
*
|
||||||
@ -25,7 +27,7 @@
|
|||||||
* makes use of the operating system calls provided.
|
* makes use of the operating system calls provided.
|
||||||
* @ingroup message_queue
|
* @ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
friend class MessageQueueSenderIF;
|
friend class MessageQueueSenderIF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -42,104 +44,24 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(uint32_t messageDepth = 3,
|
MessageQueue(uint32_t messageDepth = 3,
|
||||||
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
|
/** Copying message queues forbidden */
|
||||||
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
|
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The destructor deletes the formerly created message queue.
|
* @brief The destructor deletes the formerly created message queue.
|
||||||
* @details This is accomplished by using the delete call provided by the operating system.
|
* @details This is accomplished by using the delete call provided by the operating system.
|
||||||
*/
|
*/
|
||||||
virtual ~MessageQueue();
|
virtual ~MessageQueue();
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
|
||||||
* its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
|
||||||
* queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
|
||||||
* queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
|
||||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
|
||||||
* information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using the stored
|
|
||||||
* lastParnter information as destination. If there was no message received yet
|
|
||||||
* (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This function reads available messages from the message queue and returns the
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
* sender.
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
* sender's queue id.
|
MessageQueueId_t sentFrom, bool ignoreFault = false) override;
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details If data is available it is stored in the passed message pointer. The message's
|
|
||||||
* original content is overwritten and the sendFrom information is stored in
|
|
||||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
|
||||||
* content is cleared and the function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count);
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const;
|
|
||||||
/**
|
|
||||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
|
||||||
* \param sendTo This parameter specifies the message queue id to send the message to.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
|
|
||||||
* internal software fault counter is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
|
||||||
* \details In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -158,31 +80,10 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
bool ignoreFault = false);
|
bool ignoreFault = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
|
||||||
* attribute. If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t id;
|
|
||||||
/**
|
|
||||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
|
||||||
* to allow for replying.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t lastPartner;
|
|
||||||
/**
|
|
||||||
* @brief The message queue's name -a user specific information for the operating system- is
|
|
||||||
* generated automatically with the help of this static counter.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \brief This attribute stores a default destination to send messages to.
|
|
||||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
|
||||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t defaultDestination;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the message queue, stored for unlinking
|
* The name of the message queue, stored for unlinking
|
||||||
*/
|
*/
|
||||||
char name[16];
|
char name[16] = {};
|
||||||
|
|
||||||
static uint16_t queueCounter;
|
static uint16_t queueCounter;
|
||||||
const size_t maxMessageSize;
|
const size_t maxMessageSize;
|
||||||
|
@ -28,7 +28,11 @@ void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
|||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
if (newObject == nullptr) {
|
return addComponent(newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
|
||||||
|
if (object == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
||||||
<< " it implements ExecutableObjectIF!" << std::endl;
|
<< " it implements ExecutableObjectIF!" << std::endl;
|
||||||
@ -39,8 +43,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
|||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
objectList.push_back(newObject);
|
objectList.push_back(object);
|
||||||
newObject->setTaskIF(this);
|
object->setTaskIF(this);
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,14 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t addComponent(object_id_t object) override;
|
ReturnValue_t addComponent(object_id_t object) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an object to the list of objects to be executed.
|
||||||
|
* The objects are executed in the order added.
|
||||||
|
* @param object pointer to the object to add.
|
||||||
|
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF* object) override;
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
@ -65,9 +73,10 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
/**
|
/**
|
||||||
* @brief The function containing the actual functionality of the task.
|
* @brief The function containing the actual functionality of the task.
|
||||||
* @details The method sets and starts
|
* @details The method sets and starts
|
||||||
* the task's period, then enters a loop that is repeated indefinitely. Within the loop,
|
* the task's period, then enters a loop that is repeated indefinitely. Within
|
||||||
* all performOperation methods of the added objects are called. Afterwards the task will be
|
* the loop, all performOperation methods of the added objects are called. Afterwards the task
|
||||||
* blocked until the next period. On missing the deadline, the deadlineMissedFunction is executed.
|
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
|
||||||
|
* executed.
|
||||||
*/
|
*/
|
||||||
virtual void taskFunctionality(void);
|
virtual void taskFunctionality(void);
|
||||||
/**
|
/**
|
||||||
|
@ -28,8 +28,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
#include "fsfw/ipc/MutexGuard.h"
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
|
|
||||||
uint16_t Clock::leapSeconds = 0;
|
|
||||||
MutexIF* Clock::timeMutex = nullptr;
|
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) {
|
uint32_t Clock::getTicksPerSecond(void) {
|
||||||
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
|
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
|
||||||
return static_cast<uint32_t>(ticks_per_second);
|
return static_cast<uint32_t>(ticks_per_second);
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size, MqArgs* args)
|
||||||
: id(0), lastPartner(0), defaultDestination(NO_QUEUE), internalErrorReporter(nullptr) {
|
: MessageQueueBase(MessageQueueIF::NO_QUEUE, MessageQueueIF::NO_QUEUE, args),
|
||||||
|
internalErrorReporter(nullptr) {
|
||||||
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
|
rtems_name name = ('Q' << 24) + (queueCounter++ << 8);
|
||||||
rtems_status_code status =
|
rtems_status_code status =
|
||||||
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
|
rtems_message_queue_create(name, message_depth, max_message_size, 0, &(this->id));
|
||||||
@ -16,43 +17,19 @@ MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size)
|
|||||||
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
|
sif::error << "MessageQueue::MessageQueue: Creating Queue " << std::hex << name << std::dec
|
||||||
<< " failed with status:" << (uint32_t)status << std::endl;
|
<< " failed with status:" << (uint32_t)status << std::endl;
|
||||||
#endif
|
#endif
|
||||||
this->id = 0;
|
this->id = MessageQueueIF::NO_QUEUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
|
MessageQueue::~MessageQueue() { rtems_message_queue_delete(id); }
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault) {
|
|
||||||
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
|
|
||||||
return sendToDefaultFrom(message, this->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
|
|
||||||
if (this->lastPartner != 0) {
|
|
||||||
return sendMessage(this->lastPartner, message, this->getId());
|
|
||||||
} else {
|
|
||||||
return NO_REPLY_PARTNER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t* receivedFrom) {
|
|
||||||
ReturnValue_t status = this->receiveMessage(message);
|
|
||||||
*receivedFrom = this->lastPartner;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
rtems_status_code status =
|
rtems_status_code status =
|
||||||
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
|
rtems_message_queue_receive(id, message->getBuffer(), &size, RTEMS_NO_WAIT, 1);
|
||||||
if (status == RTEMS_SUCCESSFUL) {
|
if (status == RTEMS_SUCCESSFUL) {
|
||||||
message->setMessageSize(size);
|
message->setMessageSize(size);
|
||||||
this->lastPartner = message->getSender();
|
this->last = message->getSender();
|
||||||
// Check size of incoming message.
|
// Check size of incoming message.
|
||||||
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
if (message->getMessageSize() < message->getMinimumMessageSize()) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
@ -65,19 +42,11 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
|
|||||||
return convertReturnCode(status);
|
return convertReturnCode(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getLastPartner() const { return this->lastPartner; }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
ReturnValue_t MessageQueue::flush(uint32_t* count) {
|
||||||
rtems_status_code status = rtems_message_queue_flush(id, count);
|
rtems_status_code status = rtems_message_queue_flush(id, count);
|
||||||
return convertReturnCode(status);
|
return convertReturnCode(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getId() const { return this->id; }
|
|
||||||
|
|
||||||
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
|
|
||||||
this->defaultDestination = defaultDestination;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
MessageQueueId_t sentFrom, bool ignoreFault) {
|
||||||
message->setSender(sentFrom);
|
message->setSender(sentFrom);
|
||||||
@ -103,15 +72,6 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
|
|||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom, bool ignoreFault) {
|
|
||||||
return sendMessageFrom(defaultDestination, message, sentFrom, ignoreFault);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageQueueId_t MessageQueue::getDefaultDestination() const { return this->defaultDestination; }
|
|
||||||
|
|
||||||
bool MessageQueue::isDefaultDestinationSet() const { return (defaultDestination != NO_QUEUE); }
|
|
||||||
|
|
||||||
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
|
ReturnValue_t MessageQueue::convertReturnCode(rtems_status_code inValue) {
|
||||||
switch (inValue) {
|
switch (inValue) {
|
||||||
case RTEMS_SUCCESSFUL:
|
case RTEMS_SUCCESSFUL:
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
#ifndef FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||||
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
#define FSFW_OSAL_RTEMS_MESSAGEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/MessageQueueBase.h>
|
||||||
|
|
||||||
#include "RtemsBasic.h"
|
#include "RtemsBasic.h"
|
||||||
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
#include "fsfw/internalerror/InternalErrorReporterIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueIF.h"
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
#include "fsfw/ipc/MessageQueueMessage.h"
|
#include "fsfw/ipc/MessageQueueMessage.h"
|
||||||
|
#include "fsfw/ipc/definitions.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This class manages sending and receiving of message queue messages.
|
* @brief This class manages sending and receiving of message queue messages.
|
||||||
@ -19,7 +22,7 @@
|
|||||||
*as well as sending and receiving messages, the class makes use of the operating system calls
|
*as well as sending and receiving messages, the class makes use of the operating system calls
|
||||||
*provided. \ingroup message_queue
|
*provided. \ingroup message_queue
|
||||||
*/
|
*/
|
||||||
class MessageQueue : public MessageQueueIF {
|
class MessageQueue : public MessageQueueBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief The constructor initializes and configures the message queue.
|
* @brief The constructor initializes and configures the message queue.
|
||||||
@ -34,131 +37,26 @@ class MessageQueue : public MessageQueueIF {
|
|||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t message_depth = 3,
|
MessageQueue(size_t message_depth = 3,
|
||||||
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE);
|
size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE,
|
||||||
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
|
/** Copying message queues forbidden */
|
||||||
|
MessageQueue(const MessageQueue&) = delete;
|
||||||
|
MessageQueue& operator=(const MessageQueue&) = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The destructor deletes the formerly created message queue.
|
* @brief The destructor deletes the formerly created message queue.
|
||||||
* @details This is accomplished by using the delete call provided by the operating system.
|
* @details This is accomplished by using the delete call provided by the operating system.
|
||||||
*/
|
*/
|
||||||
virtual ~MessageQueue();
|
virtual ~MessageQueue();
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the given destination.
|
|
||||||
* @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes
|
|
||||||
* its queue id as "sentFrom" parameter.
|
|
||||||
* @param sendTo This parameter specifies the message queue id of the destination message
|
|
||||||
* queue.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
* @param ignoreFault If set to true, the internal software fault counter is not incremented if
|
|
||||||
* queue is full.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendMessage(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the default destination.
|
|
||||||
* @details As in the sendMessage method, this function uses the sendToDefault call of the
|
|
||||||
* MessageQueueSender parent class and adds its queue id as "sentFrom"
|
|
||||||
* information.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t sendToDefault(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* @brief This operation sends a message to the last communication partner.
|
|
||||||
* @details This operation simplifies answering an incoming message by using the stored
|
|
||||||
* lastParnter information as destination. If there was no message received yet
|
|
||||||
* (i.e. lastPartner is zero), an error code is returned.
|
|
||||||
* @param message A pointer to a previously created message, which is sent.
|
|
||||||
*/
|
|
||||||
ReturnValue_t reply(MessageQueueMessageIF* message);
|
|
||||||
|
|
||||||
/**
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
* @brief This function reads available messages from the message queue and returns the
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
* sender.
|
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
* @details It works identically to the other receiveMessage call, but in addition returns the
|
|
||||||
* sender's queue id.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, MessageQueueId_t* receivedFrom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function reads available messages from the message queue.
|
|
||||||
* @details If data is available it is stored in the passed message pointer. The message's
|
|
||||||
* original content is overwritten and the sendFrom information is stored in
|
|
||||||
* the lastPartner attribute. Else, the lastPartner information remains untouched, the message's
|
|
||||||
* content is cleared and the function returns immediately.
|
|
||||||
* @param message A pointer to a message in which the received data is stored.
|
|
||||||
*/
|
|
||||||
ReturnValue_t receiveMessage(MessageQueueMessageIF* message);
|
|
||||||
/**
|
|
||||||
* Deletes all pending messages in the queue.
|
|
||||||
* @param count The number of flushed messages.
|
|
||||||
* @return RETURN_OK on success.
|
|
||||||
*/
|
|
||||||
ReturnValue_t flush(uint32_t* count);
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of the last communication partner.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getLastPartner() const;
|
|
||||||
/**
|
|
||||||
* @brief This method returns the message queue id of this class's message queue.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getId() const;
|
|
||||||
/**
|
|
||||||
* \brief With the sendMessage call, a queue message is sent to a receiving queue.
|
|
||||||
* \details This method takes the message provided, adds the sentFrom information and passes
|
|
||||||
* it on to the destination provided with an operating system call. The OS's
|
|
||||||
* return value is returned.
|
|
||||||
* \param sendTo This parameter specifies the message queue id to send the message to.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default. \param ignoreFault If set to true, the
|
|
||||||
* internal software fault counter is not incremented if queue is full.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom = NO_QUEUE,
|
||||||
bool ignoreFault = false);
|
bool ignoreFault = false) override;
|
||||||
/**
|
|
||||||
* \brief The sendToDefault method sends a queue message to the default destination.
|
|
||||||
* \details In all other aspects, it works identical to the sendMessage method.
|
|
||||||
* \param message This is a pointer to a previously created message, which is sent.
|
|
||||||
* \param sentFrom The sentFrom information can be set to inject the sender's queue id into the
|
|
||||||
* message. This variable is set to zero by default.
|
|
||||||
*/
|
|
||||||
virtual ReturnValue_t sendToDefaultFrom(MessageQueueMessageIF* message,
|
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
|
||||||
bool ignoreFault = false);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple setter for the default destination.
|
|
||||||
*/
|
|
||||||
void setDefaultDestination(MessageQueueId_t defaultDestination);
|
|
||||||
/**
|
|
||||||
* \brief This method is a simple getter for the default destination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t getDefaultDestination() const;
|
|
||||||
|
|
||||||
bool isDefaultDestinationSet() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* @brief The class stores the queue id it got assigned from the operating system in this
|
|
||||||
* attribute. If initialization fails, the queue id is set to zero.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t id;
|
|
||||||
/**
|
|
||||||
* @brief In this attribute, the queue id of the last communication partner is stored
|
|
||||||
* to allow for replying.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t lastPartner;
|
|
||||||
/**
|
|
||||||
* @brief The message queue's name -a user specific information for the operating system- is
|
|
||||||
* generated automatically with the help of this static counter.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \brief This attribute stores a default destination to send messages to.
|
|
||||||
* \details It is stored to simplify sending to always-the-same receiver. The attribute may
|
|
||||||
* be set in the constructor or by a setter call to setDefaultDestination.
|
|
||||||
*/
|
|
||||||
MessageQueueId_t defaultDestination;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief This attribute stores a reference to the internal error reporter for reporting full
|
* \brief This attribute stores a reference to the internal error reporter for reporting full
|
||||||
* queues. \details In the event of a full destination queue, the reporter will be notified. The
|
* queues. \details In the event of a full destination queue, the reporter will be notified. The
|
||||||
|
@ -68,11 +68,15 @@ void PeriodicTask::taskFunctionality() {
|
|||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
||||||
if (newObject == nullptr) {
|
return addComponent(newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
||||||
|
if (object == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
objectList.push_back(newObject);
|
objectList.push_back(object);
|
||||||
newObject->setTaskIF(this);
|
object->setTaskIF(this);
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ class ExecutableObjectIF;
|
|||||||
* @brief This class represents a specialized task for periodic activities of multiple objects.
|
* @brief This class represents a specialized task for periodic activities of multiple objects.
|
||||||
*
|
*
|
||||||
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
|
* @details MultiObjectTask is an extension to ObjectTask in the way that it is able to execute
|
||||||
* multiple objects that implement the ExecutableObjectIF interface. The objects must
|
* multiple objects that implement the ExecutableObjectIF interface. The
|
||||||
* be added prior to starting the task.
|
* objects must be added prior to starting the task.
|
||||||
* @author baetz
|
* @author baetz
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
@ -59,6 +59,14 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t addComponent(object_id_t object) override;
|
ReturnValue_t addComponent(object_id_t object) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an object to the list of objects to be executed.
|
||||||
|
* The objects are executed in the order added.
|
||||||
|
* @param object pointer to the object to add.
|
||||||
|
* @return RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
||||||
|
*/
|
||||||
|
ReturnValue_t addComponent(ExecutableObjectIF *object) override;
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
uint32_t getPeriodMs() const override;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
@ -49,8 +49,9 @@ QueueFactory::QueueFactory() {}
|
|||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() {}
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize) {
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
return new MessageQueue(messageDepth, maxMessageSize);
|
MqArgs* args) {
|
||||||
|
return new MessageQueue(messageDepth, maxMessageSize, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { delete queue; }
|
||||||
|
@ -25,8 +25,8 @@ class RTEMSTaskBase {
|
|||||||
* all other attributes are set with default values.
|
* all other attributes are set with default values.
|
||||||
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
|
* @param priority Sets the priority of a task. Values range from a low 0 to a high 99.
|
||||||
* @param stack_size The stack size reserved by the operating system for the task.
|
* @param stack_size The stack size reserved by the operating system for the task.
|
||||||
* @param nam The name of the Task, as a null-terminated String. Currently max 4 chars
|
* @param nam The name of the Task, as a null-terminated String. Currently max 4
|
||||||
* supported (excluding Null-terminator), rest will be truncated
|
* chars supported (excluding Null-terminator), rest will be truncated
|
||||||
*/
|
*/
|
||||||
RTEMSTaskBase(rtems_task_priority priority, size_t stack_size, const char *name);
|
RTEMSTaskBase(rtems_task_priority priority, size_t stack_size, const char *name);
|
||||||
/**
|
/**
|
||||||
|
@ -51,9 +51,9 @@ class RMAP : public HasReturnvaluesIF {
|
|||||||
// MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write
|
// MAKE_RETURN_CODE(0xE4); //the data that was to be sent was too long for the hw to handle (write
|
||||||
// command) or the expected len was bigger than maximal expected len (read command) command was
|
// command) or the expected len was bigger than maximal expected len (read command) command was
|
||||||
// not sent
|
// not sent
|
||||||
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t COMMAND_NULLPOINTER
|
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t
|
||||||
// = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write command, or
|
// COMMAND_NULLPOINTER = MAKE_RETURN_CODE(0xE5); //datalen was != 0 but data was == NULL in write
|
||||||
// nullpointer in read command
|
// command, or nullpointer in read command
|
||||||
static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED =
|
static const ReturnValue_t COMMAND_CHANNEL_DEACTIVATED =
|
||||||
MAKE_RETURN_CODE(0xE6); // the channel has no port set
|
MAKE_RETURN_CODE(0xE6); // the channel has no port set
|
||||||
static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE =
|
static const ReturnValue_t COMMAND_PORT_OUT_OF_RANGE =
|
||||||
@ -73,8 +73,8 @@ class RMAP : public HasReturnvaluesIF {
|
|||||||
static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE(
|
static const ReturnValue_t REPLY_MISSMATCH = MAKE_RETURN_CODE(
|
||||||
0xD3); // a read command was issued, but get_write_rply called, or other way round
|
0xD3); // a read command was issued, but get_write_rply called, or other way round
|
||||||
static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4); // timeout
|
static const ReturnValue_t REPLY_TIMEOUT = MAKE_RETURN_CODE(0xD4); // timeout
|
||||||
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER =
|
// replaced by DeviceCommunicationIF::NULLPOINTER static const ReturnValue_t REPLY_NULLPOINTER
|
||||||
// MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL return values for
|
// = MAKE_RETURN_CODE(0xD5);//one of the arguments in a read reply was NULL return values for
|
||||||
// get_reply
|
// get_reply
|
||||||
static const ReturnValue_t REPLY_INTERFACE_BUSY =
|
static const ReturnValue_t REPLY_INTERFACE_BUSY =
|
||||||
MAKE_RETURN_CODE(0xC0); // Interface is busy (transmission buffer still being processed)
|
MAKE_RETURN_CODE(0xC0); // Interface is busy (transmission buffer still being processed)
|
||||||
@ -169,8 +169,8 @@ class RMAP : public HasReturnvaluesIF {
|
|||||||
* @param buffer the data to write
|
* @param buffer the data to write
|
||||||
* @param length length of data
|
* @param length length of data
|
||||||
* @return
|
* @return
|
||||||
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write
|
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was ==
|
||||||
* command
|
* NULL in write command
|
||||||
* - return codes of RMAPChannelIF::sendCommand()
|
* - return codes of RMAPChannelIF::sendCommand()
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length);
|
static ReturnValue_t sendWriteCommand(RMAPCookie *cookie, const uint8_t *buffer, size_t length);
|
||||||
@ -205,8 +205,8 @@ class RMAP : public HasReturnvaluesIF {
|
|||||||
* @param cookie to cookie to read from
|
* @param cookie to cookie to read from
|
||||||
* @param expLength the expected maximum length of the reply
|
* @param expLength the expected maximum length of the reply
|
||||||
* @return
|
* @return
|
||||||
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was == NULL in write
|
* - @c COMMAND_NULLPOINTER datalen was != 0 but data was ==
|
||||||
* command, or nullpointer in read command
|
* NULL in write command, or nullpointer in read command
|
||||||
* - return codes of RMAPChannelIF::sendCommand()
|
* - return codes of RMAPChannelIF::sendCommand()
|
||||||
*/
|
*/
|
||||||
static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength);
|
static ReturnValue_t sendReadCommand(RMAPCookie *cookie, uint32_t expLength);
|
||||||
|
@ -73,16 +73,16 @@ class RMAPChannelIF {
|
|||||||
* @param datalen length of data
|
* @param datalen length of data
|
||||||
* @return
|
* @return
|
||||||
* - @c RETURN_OK
|
* - @c RETURN_OK
|
||||||
* - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending command;
|
* - @c COMMAND_NO_DESCRIPTORS_AVAILABLE no descriptors available for sending
|
||||||
* command was not sent
|
* command; command was not sent
|
||||||
* - @c COMMAND_BUFFER_FULL no receiver buffer available for expected len; command
|
* - @c COMMAND_BUFFER_FULL no receiver buffer available for
|
||||||
* was not sent
|
* expected len; command was not sent
|
||||||
* - @c COMMAND_TOO_BIG the data that was to be sent was too long for the hw to
|
* - @c COMMAND_TOO_BIG the data that was to be sent was too
|
||||||
* handle (write command) or the expected len was bigger than maximal expected len (read command)
|
* long for the hw to handle (write command) or the expected len was bigger than maximal expected
|
||||||
* command was not sent
|
* len (read command) command was not sent
|
||||||
* - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set
|
* - @c COMMAND_CHANNEL_DEACTIVATED the channel has no port set
|
||||||
* - @c NOT_SUPPORTED if you dont feel like implementing
|
* - @c NOT_SUPPORTED if you dont feel like
|
||||||
* something...
|
* implementing something...
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, const uint8_t *data,
|
virtual ReturnValue_t sendCommand(RMAPCookie *cookie, uint8_t instruction, const uint8_t *data,
|
||||||
size_t datalen) = 0;
|
size_t datalen) = 0;
|
||||||
@ -97,8 +97,8 @@ class RMAPChannelIF {
|
|||||||
* - @c REPLY_NO_REPLY no reply was received
|
* - @c REPLY_NO_REPLY no reply was received
|
||||||
* - @c REPLY_NOT_SENT command was not sent, implies no reply
|
* - @c REPLY_NOT_SENT command was not sent, implies no reply
|
||||||
* - @c REPLY_NOT_YET_SENT command is still waiting to be sent
|
* - @c REPLY_NOT_YET_SENT command is still waiting to be sent
|
||||||
* - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission buffer still being
|
* - @c WRITE_REPLY_INTERFACE_BUSY Interface is busy (transmission
|
||||||
* processed)
|
* buffer still being processed)
|
||||||
* - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last
|
* - @c WRITE_REPLY_TRANSMISSION_ERROR Interface encountered errors during last
|
||||||
* operation, data could not be processed. (transmission error)
|
* operation, data could not be processed. (transmission error)
|
||||||
* - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value)
|
* - @c WRITE_REPLY_INVALID_DATA Invalid data (amount / value)
|
||||||
|
@ -32,10 +32,10 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C
|
|||||||
static const uint8_t RMAP_REPLY_WRITE =
|
static const uint8_t RMAP_REPLY_WRITE =
|
||||||
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
|
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
|
||||||
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
|
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
|
||||||
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE) |
|
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
|
||||||
//(1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
|
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
|
||||||
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
|
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
|
||||||
//RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
||||||
|
|
||||||
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||||
//(1<<RMAP_COMMAND_BIT_REPLY))
|
//(1<<RMAP_COMMAND_BIT_REPLY))
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
#ifndef FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
||||||
#define FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
#define FSFW_SERVICEINTERFACE_SERVICEINTERFACEPRINTER
|
||||||
|
|
||||||
|
#include "fsfw/FSFW.h"
|
||||||
|
|
||||||
#if FSFW_DISABLE_PRINTOUT == 0
|
#if FSFW_DISABLE_PRINTOUT == 0
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#endif
|
#endif
|
||||||
|
@ -110,7 +110,7 @@ ReturnValue_t LocalPool::modifyData(store_address_t storeId, uint8_t** packetPtr
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
|
ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
|
||||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
#if FSFW_VERBOSE_LEVEL >= 2
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex
|
sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex
|
||||||
<< " Index: " << storeId.packetIndex << std::endl;
|
<< " Index: " << storeId.packetIndex << std::endl;
|
||||||
@ -148,7 +148,7 @@ ReturnValue_t LocalPool::deleteData(uint8_t* ptr, size_t size, store_address_t*
|
|||||||
// element of an object.
|
// element of an object.
|
||||||
localId.packetIndex = deltaAddress / elementSizes[n];
|
localId.packetIndex = deltaAddress / elementSizes[n];
|
||||||
result = deleteData(localId);
|
result = deleteData(localId);
|
||||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
#if FSFW_VERBOSE_LEVEL >= 2
|
||||||
if (deltaAddress % elementSizes[n] != 0) {
|
if (deltaAddress % elementSizes[n] != 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "LocalPool::deleteData: Address not aligned!" << std::endl;
|
sif::error << "LocalPool::deleteData: Address not aligned!" << std::endl;
|
||||||
@ -219,7 +219,7 @@ ReturnValue_t LocalPool::reserveSpace(const size_t size, store_address_t* storeI
|
|||||||
status = findEmpty(storeId->poolIndex, &storeId->packetIndex);
|
status = findEmpty(storeId->poolIndex, &storeId->packetIndex);
|
||||||
}
|
}
|
||||||
if (status == RETURN_OK) {
|
if (status == RETURN_OK) {
|
||||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
#if FSFW_VERBOSE_LEVEL >= 2
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "Reserve: Pool: " << std::dec << storeId->poolIndex
|
sif::debug << "Reserve: Pool: " << std::dec << storeId->poolIndex
|
||||||
<< " Index: " << storeId->packetIndex << std::endl;
|
<< " Index: " << storeId->packetIndex << std::endl;
|
||||||
@ -257,7 +257,7 @@ void LocalPool::setToSpillToHigherPools(bool enable) { this->spillsToHigherPools
|
|||||||
ReturnValue_t LocalPool::getSubPoolIndex(size_t packetSize, uint16_t* subpoolIndex,
|
ReturnValue_t LocalPool::getSubPoolIndex(size_t packetSize, uint16_t* subpoolIndex,
|
||||||
uint16_t startAtIndex) {
|
uint16_t startAtIndex) {
|
||||||
for (uint16_t n = startAtIndex; n < NUMBER_OF_SUBPOOLS; n++) {
|
for (uint16_t n = startAtIndex; n < NUMBER_OF_SUBPOOLS; n++) {
|
||||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
#if FSFW_VERBOSE_LEVEL >= 2
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n
|
sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: " << n
|
||||||
<< ", Element Size: " << elementSizes[n] << std::endl;
|
<< ", Element Size: " << elementSizes[n] << std::endl;
|
||||||
|
@ -17,7 +17,7 @@ ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* addr
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
|
ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
|
||||||
#if FSFW_VERBOSE_PRINTOUT == 2
|
#if FSFW_VERBOSE_LEVEL >= 2
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store "
|
sif::debug << "PoolManager( " << translateObject(getObjectId()) << " )::deleteData from store "
|
||||||
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
||||||
|
@ -26,21 +26,25 @@ class PeriodicTaskIF {
|
|||||||
virtual ReturnValue_t startTask() = 0;
|
virtual ReturnValue_t startTask() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a component (object) to a periodic task. The pointer to the
|
* Add a component (object) to a periodic task.
|
||||||
* task can be set optionally
|
|
||||||
* @param object
|
* @param object
|
||||||
* Add an object to the task. The most important case is to add an
|
* Add an object to the task. The object needs to implement ExecutableObjectIF
|
||||||
* executable object with a function which will be called regularly
|
|
||||||
* (see ExecutableObjectIF)
|
|
||||||
* @param setTaskIF
|
|
||||||
* Can be used to specify whether the task object pointer is passed
|
|
||||||
* to the component.
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t addComponent(object_id_t object) {
|
virtual ReturnValue_t addComponent(object_id_t object) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an object to a periodic task.
|
||||||
|
* @param object
|
||||||
|
* Add an object to the task.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
virtual ReturnValue_t addComponent(ExecutableObjectIF* object) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
};
|
||||||
|
|
||||||
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
|
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
|
||||||
|
|
||||||
virtual uint32_t getPeriodMs() const = 0;
|
virtual uint32_t getPeriodMs() const = 0;
|
||||||
|
@ -91,7 +91,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const uint8_t* f
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return convertTimevalToTimeOfDay(to, &time);
|
return Clock::convertTimevalToTimeOfDay(&time, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
|
ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* from,
|
||||||
@ -109,8 +109,8 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f
|
|||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
// At this point we made sure that this is a valid ccs time
|
||||||
Ccs_mseconds* temp = (Ccs_mseconds*)from;
|
const Ccs_mseconds* temp = reinterpret_cast<const Ccs_mseconds*>(from);
|
||||||
|
|
||||||
to->year = (temp->yearMSB << 8) + temp->yearLSB;
|
to->year = (temp->yearMSB << 8) + temp->yearLSB;
|
||||||
to->hour = temp->hour;
|
to->hour = temp->hour;
|
||||||
@ -118,16 +118,19 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f
|
|||||||
to->second = temp->second;
|
to->second = temp->second;
|
||||||
|
|
||||||
if (temp->pField & (1 << 3)) { // day of year variation
|
if (temp->pField & (1 << 3)) { // day of year variation
|
||||||
uint16_t tempDay = (temp->month << 8) + temp->day;
|
uint16_t tempDayOfYear = (temp->month << 8) + temp->day;
|
||||||
result = convertDaysOfYear(tempDay, to->year, &(temp->month), &(temp->day));
|
uint8_t tempDay = 0;
|
||||||
|
uint8_t tempMonth = 0;
|
||||||
|
result = convertDaysOfYear(tempDayOfYear, to->year, &tempMonth, &tempDay);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
to->month = tempMonth;
|
||||||
|
to->day = tempDay;
|
||||||
|
} else {
|
||||||
to->month = temp->month;
|
to->month = temp->month;
|
||||||
to->day = temp->day;
|
to->day = temp->day;
|
||||||
|
}
|
||||||
to->usecond = 0;
|
to->usecond = 0;
|
||||||
if (subsecondsLength > 0) {
|
if (subsecondsLength > 0) {
|
||||||
*foundLength += 1;
|
*foundLength += 1;
|
||||||
@ -162,7 +165,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
uint16_t hour;
|
uint16_t hour;
|
||||||
uint16_t minute;
|
uint16_t minute;
|
||||||
float second;
|
float second;
|
||||||
int count = sscanf((char*)from,
|
int count = sscanf((const char*)from,
|
||||||
"%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16
|
"%4" SCNu16 "-%2" SCNu16 "-%2" SCNu16
|
||||||
"T%"
|
"T%"
|
||||||
"2" SCNu16 ":%2" SCNu16 ":%fZ",
|
"2" SCNu16 ":%2" SCNu16 ":%fZ",
|
||||||
@ -179,7 +182,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try Code B (yyyy-ddd)
|
// try Code B (yyyy-ddd)
|
||||||
count = sscanf((char*)from,
|
count = sscanf((const char*)from,
|
||||||
"%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16
|
"%4" SCNu16 "-%3" SCNu16 "T%2" SCNu16
|
||||||
":%"
|
":%"
|
||||||
"2" SCNu16 ":%fZ",
|
"2" SCNu16 ":%fZ",
|
||||||
@ -211,7 +214,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
float second;
|
float second;
|
||||||
// try Code A (yyyy-mm-dd)
|
// try Code A (yyyy-mm-dd)
|
||||||
int count =
|
int count =
|
||||||
sscanf((char*)from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ",
|
sscanf((const char*)from, "%4" SCNu16 "-%2" SCNu8 "-%2" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ",
|
||||||
&year, &month, &day, &hour, &minute, &second);
|
&year, &month, &day, &hour, &minute, &second);
|
||||||
if (count == 6) {
|
if (count == 6) {
|
||||||
to->year = year;
|
to->year = year;
|
||||||
@ -225,8 +228,8 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try Code B (yyyy-ddd)
|
// try Code B (yyyy-ddd)
|
||||||
count = sscanf((char*)from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year, &day,
|
count = sscanf((const char*)from, "%4" SCNu16 "-%3" SCNu16 "T%2" SCNu8 ":%2" SCNu8 ":%fZ", &year,
|
||||||
&hour, &minute, &second);
|
&day, &hour, &minute, &second);
|
||||||
if (count == 5) {
|
if (count == 5) {
|
||||||
uint8_t tempDay;
|
uint8_t tempDay;
|
||||||
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, &tempDay);
|
ReturnValue_t result = CCSDSTime::convertDaysOfYear(day, year, &month, &tempDay);
|
||||||
@ -248,7 +251,7 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
||||||
Ccs_mseconds* time_struct = (Ccs_mseconds*)time;
|
const Ccs_mseconds* time_struct = reinterpret_cast<const Ccs_mseconds*>(time);
|
||||||
|
|
||||||
uint8_t additionalBytes = time_struct->pField & 0b111;
|
uint8_t additionalBytes = time_struct->pField & 0b111;
|
||||||
if ((additionalBytes == 0b111) || (length < (additionalBytes + 8))) {
|
if ((additionalBytes == 0b111) || (length < (additionalBytes + 8))) {
|
||||||
@ -278,7 +281,7 @@ ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
|||||||
return INVALID_TIME_FORMAT;
|
return INVALID_TIME_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* additionalByte = &time_struct->secondEminus2;
|
const uint8_t* additionalByte = &time_struct->secondEminus2;
|
||||||
|
|
||||||
for (; additionalBytes != 0; additionalBytes--) {
|
for (; additionalBytes != 0; additionalBytes--) {
|
||||||
if (*additionalByte++ > 99) {
|
if (*additionalByte++ > 99) {
|
||||||
@ -486,11 +489,6 @@ ReturnValue_t CCSDSTime::checkTimeOfDay(const Clock::TimeOfDay_t* time) {
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, timeval* from) {
|
|
||||||
// This is rather tricky. Implement only if needed. Also, if so, move to OSAL.
|
|
||||||
return UNSUPPORTED_TIME_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
|
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t* foundLength,
|
||||||
size_t maxLength) {
|
size_t maxLength) {
|
||||||
uint8_t pField = *from;
|
uint8_t pField = *from;
|
||||||
@ -554,6 +552,35 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const uint8_t* from, size_t
|
|||||||
return RETURN_OK;
|
return RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short* from) {
|
||||||
|
if (to == nullptr or from == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
uint16_t days = (from->dayMSB << 8) + from->dayLSB;
|
||||||
|
if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) {
|
||||||
|
return INVALID_TIME_FORMAT;
|
||||||
|
}
|
||||||
|
days -= DAYS_CCSDS_TO_UNIX_EPOCH;
|
||||||
|
to->tv_sec = days * SECONDS_PER_DAY;
|
||||||
|
uint32_t msDay =
|
||||||
|
(from->msDay_hh << 24) + (from->msDay_h << 16) + (from->msDay_l << 8) + from->msDay_ll;
|
||||||
|
to->tv_sec += (msDay / 1000);
|
||||||
|
to->tv_usec = (msDay % 1000) * 1000;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CCSDSTime::convertFromCDS(Clock::TimeOfDay_t* to, const CCSDSTime::CDS_short* from) {
|
||||||
|
if (to == nullptr or from == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
timeval tempTimeval;
|
||||||
|
ReturnValue_t result = convertFromCDS(&tempTimeval, from);
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return Clock::convertTimevalToTimeOfDay(&tempTimeval, to);
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
ReturnValue_t CCSDSTime::convertFromCUC(timeval* to, uint8_t pField, const uint8_t* from,
|
||||||
size_t* foundLength, size_t maxLength) {
|
size_t* foundLength, size_t maxLength) {
|
||||||
uint32_t secs = 0;
|
uint32_t secs = 0;
|
||||||
|
@ -180,6 +180,8 @@ class CCSDSTime : public HasReturnvaluesIF {
|
|||||||
|
|
||||||
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength,
|
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, size_t *foundLength,
|
||||||
size_t maxLength);
|
size_t maxLength);
|
||||||
|
static ReturnValue_t convertFromCDS(timeval *to, const CCSDSTime::CDS_short *from);
|
||||||
|
static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, const CCSDSTime::CDS_short *from);
|
||||||
|
|
||||||
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from,
|
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, uint8_t const *from,
|
||||||
size_t *foundLength, size_t maxLength);
|
size_t *foundLength, size_t maxLength);
|
||||||
@ -221,7 +223,6 @@ class CCSDSTime : public HasReturnvaluesIF {
|
|||||||
uint8_t *day);
|
uint8_t *day);
|
||||||
|
|
||||||
static bool isLeapYear(uint32_t year);
|
static bool isLeapYear(uint32_t year);
|
||||||
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t *to, timeval *from);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */
|
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */
|
||||||
|
@ -99,6 +99,13 @@ class Clock {
|
|||||||
*/
|
*/
|
||||||
static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
|
static ReturnValue_t getDateAndTime(TimeOfDay_t *time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to time of day struct given the POSIX timeval struct
|
||||||
|
* @param from
|
||||||
|
* @param to
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
|
||||||
/**
|
/**
|
||||||
* Converts a time of day struct to POSIX seconds.
|
* Converts a time of day struct to POSIX seconds.
|
||||||
* @param time The time of day as input
|
* @param time The time of day as input
|
||||||
@ -166,6 +173,7 @@ class Clock {
|
|||||||
|
|
||||||
static MutexIF *timeMutex;
|
static MutexIF *timeMutex;
|
||||||
static uint16_t leapSeconds;
|
static uint16_t leapSeconds;
|
||||||
|
static bool leapSecondsSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexGuard.h"
|
#include "fsfw/ipc/MutexGuard.h"
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
|
|
||||||
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval *tt) {
|
uint16_t Clock::leapSeconds = 0;
|
||||||
|
MutexIF* Clock::timeMutex = nullptr;
|
||||||
|
bool Clock::leapSecondsSet = false;
|
||||||
|
|
||||||
|
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
|
||||||
uint16_t leapSeconds;
|
uint16_t leapSeconds;
|
||||||
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
ReturnValue_t result = getLeapSeconds(&leapSeconds);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
@ -27,12 +33,16 @@ ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
|
|||||||
MutexGuard helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
|
|
||||||
leapSeconds = leapSeconds_;
|
leapSeconds = leapSeconds_;
|
||||||
|
leapSecondsSet = true;
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
|
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
|
||||||
if (timeMutex == nullptr) {
|
if (not leapSecondsSet) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
MutexGuard helper(timeMutex);
|
MutexGuard helper(timeMutex);
|
||||||
@ -42,9 +52,32 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t *leapSeconds_) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
|
||||||
|
struct tm* timeInfo;
|
||||||
|
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
|
||||||
|
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
|
||||||
|
// this implementation
|
||||||
|
ReturnValue_t result = checkOrCreateClockMutex();
|
||||||
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
MutexGuard helper(timeMutex);
|
||||||
|
// gmtime writes its output in a global buffer which is not Thread Safe
|
||||||
|
// Therefore we have to use a Mutex here
|
||||||
|
timeInfo = gmtime(&from->tv_sec);
|
||||||
|
to->year = timeInfo->tm_year + 1900;
|
||||||
|
to->month = timeInfo->tm_mon + 1;
|
||||||
|
to->day = timeInfo->tm_mday;
|
||||||
|
to->hour = timeInfo->tm_hour;
|
||||||
|
to->minute = timeInfo->tm_min;
|
||||||
|
to->second = timeInfo->tm_sec;
|
||||||
|
to->usecond = from->tv_usec;
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
ReturnValue_t Clock::checkOrCreateClockMutex() {
|
||||||
if (timeMutex == nullptr) {
|
if (timeMutex == nullptr) {
|
||||||
MutexFactory *mutexFactory = MutexFactory::instance();
|
MutexFactory* mutexFactory = MutexFactory::instance();
|
||||||
if (mutexFactory == nullptr) {
|
if (mutexFactory == nullptr) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "fsfw/timemanager/Countdown.h"
|
#include "fsfw/timemanager/Countdown.h"
|
||||||
|
|
||||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {}
|
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
|
||||||
|
setTimeout(initialTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
Countdown::~Countdown() {}
|
Countdown::~Countdown() {}
|
||||||
|
|
||||||
|
23
src/fsfw/version.cpp
Normal file
23
src/fsfw/version.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "fsfw/FSFWVersion.h"
|
||||||
|
|
||||||
|
#ifdef major
|
||||||
|
#undef major
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef minor
|
||||||
|
#undef minor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const fsfw::Version fsfw::FSFW_VERSION = {FSFW_VERSION_MAJOR, FSFW_VERSION_MINOR,
|
||||||
|
FSFW_VERSION_REVISION};
|
||||||
|
|
||||||
|
fsfw::Version::Version(uint32_t major, uint32_t minor, uint32_t revision)
|
||||||
|
: major(major), minor(minor), revision(revision) {}
|
||||||
|
|
||||||
|
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||||
|
snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user