Compare commits
276 Commits
meier/deve
...
docker_d3
Author | SHA1 | Date | |
---|---|---|---|
7de56f189b | |||
541f563683 | |||
28ea71a077 | |||
a044d7d724 | |||
687700cee8 | |||
732b615cb3 | |||
394ce2ec3e | |||
dde96ae220 | |||
c3aaab4b93 | |||
edf1d5ae8d | |||
690991b4b5 | |||
1a294e6a13 | |||
8c4e34153b | |||
b60e4bcb90 | |||
b18410aa63 | |||
7f57a8784a | |||
4b33aa8262 | |||
d47a908117 | |||
fce95e04a8 | |||
fc742e4270 | |||
b5183a19fc | |||
ca453a8f16 | |||
b7c0c07141 | |||
0158102f11 | |||
69859fdbc9 | |||
90bccc744e | |||
ab89108c55 | |||
a682bbe400 | |||
e67fc2ab0d | |||
71ce966531 | |||
6b0f4a159f | |||
4a06b558c1 | |||
6d921f03fd | |||
65bc8213fe | |||
a0ee86ace8 | |||
a07a368272 | |||
cb8a4bbbec | |||
17f54006b8 | |||
395cf9cfa7 | |||
a3c0b441ec | |||
b4132800ae | |||
ad53b48fcb | |||
dee40f9079 | |||
92ec24352f | |||
3f9e459f48 | |||
e0c7f8d51d | |||
eb79386c92 | |||
4542f31c40 | |||
689fb378d8 | |||
98b711a872 | |||
800aa131fa | |||
6983980304 | |||
7c0ba59993 | |||
28873fc87b | |||
24e849ed9c | |||
d8985c141e | |||
7602b15256 | |||
d1a82bceed | |||
7292b02907 | |||
347714d53a | |||
f230fa1617 | |||
93615b100c | |||
e18d3d559e | |||
08ff061d07 | |||
cc351c1066 | |||
664a548c53 | |||
e9895559a3 | |||
eda5b8f593 | |||
e03f55604a | |||
51d7df2dba | |||
12046a2db6 | |||
c697d0f8ab | |||
c7cf8e710d | |||
7dddcdfd55 | |||
261eea381e | |||
e59f1f26bf | |||
f7cde80088 | |||
e60a665de4 | |||
34658ef7db | |||
940fd6f465 | |||
f288d5120d | |||
5a425a1c58 | |||
5e62258aa6 | |||
0b53b4873f | |||
8e2597f609 | |||
dac700b80a | |||
d0fc360697 | |||
576414438c | |||
13cda86d23 | |||
e1dd27b9dd | |||
8e9d4b451c | |||
816550b69c | |||
7fee852dbd | |||
1e7032f89c | |||
f0debecbbc | |||
ef9d7aa7d3 | |||
b8fd2db434 | |||
878e32cbe8 | |||
4821706561 | |||
eed6a64597 | |||
5736023ffa | |||
8a12a5097e | |||
87e4a57ef7 | |||
0375ee1881 | |||
c8e034d975 | |||
e98aa005cb | |||
52310f7d32 | |||
e3d1308205 | |||
970f039e85 | |||
99c72fd00b | |||
2708b71d77 | |||
5a4539def4 | |||
13a34cd677 | |||
811287aac8 | |||
23fb06578b | |||
c86e99e6dc | |||
4092de911c | |||
00952e15b0 | |||
6366283ce2 | |||
01ebf0f4d3 | |||
99fe6487c8 | |||
d4a6f987bc | |||
57bac4f262 | |||
cfa6843c8f | |||
b6b3221b22 | |||
8dc640c162 | |||
deee4c43c0 | |||
ad0b6f1ed1 | |||
ec03a674bd | |||
9e3d5b6a0c | |||
994c7299b9 | |||
57a830cb46 | |||
271057ca6b | |||
861335212e | |||
038e47a46e | |||
c215508a12 | |||
ccadbb5942 | |||
171c48495c | |||
a83b86ccd2 | |||
2e4b9bcd7c | |||
3046822e88 | |||
6442dd0c38 | |||
9b6fa646ed | |||
e77bde459b | |||
2d9d83a1c5 | |||
c561271070 | |||
70d4fc1e0a | |||
b8cfb36426 | |||
e5c140e0ae | |||
b99160e850 | |||
c4c340fde1 | |||
9a4c7589cc | |||
d11f898f70 | |||
34e124f2db | |||
e05c72b062 | |||
377c3325d2 | |||
2ca8523215 | |||
25775614de | |||
efb3d982f3 | |||
0410ecd9e3 | |||
dd986fefd3 | |||
b38329aa0e | |||
0fe1b70bae | |||
c5b4499d98 | |||
458aa5c265 | |||
4499c9bf04 | |||
eb0223bc51 | |||
be6a492022 | |||
d8bd08dd8c | |||
18c2847b08 | |||
d45cda93b2 | |||
3448292e8a | |||
d983305ea5 | |||
c83cc492c0 | |||
ece32f88f4 | |||
dd9e28fca1 | |||
46cfe65321 | |||
7b7f5d7e0a | |||
fd112ed597 | |||
96eb8fc21f | |||
88fa4f1d9d | |||
5989c88c88 | |||
da8a108cb7 | |||
75132c1e39 | |||
eb494707af | |||
736f8d0238 | |||
f1acf8e18b | |||
281f91ec5d | |||
15352b539d | |||
4015e85506 | |||
aacaf52fd9 | |||
118f1da8dd | |||
89f83f4e3d | |||
39b7976056 | |||
8b0508d50a | |||
8a40878eb5 | |||
220469a2dd | |||
83de5b4ec1 | |||
fe1c51ae6d | |||
10cc954d27 | |||
73ff9b97db | |||
b0d71597f0 | |||
226f28dc7b | |||
6308427d03 | |||
398d04dc50 | |||
80a5ed3c5b | |||
5d5a355110 | |||
c78b7c432b | |||
6bfdace512 | |||
16e55a98ce | |||
79f17843d8 | |||
e5e163bdbf | |||
4e4820af05 | |||
637512ad77 | |||
a4bd5a2aaa | |||
a943e4eebb | |||
cb0c80d8dc | |||
3332f68ce7 | |||
2fbf847367 | |||
54feb77770 | |||
57e6c46e72 | |||
a3617cad11 | |||
7801c6effe | |||
b62c19a364 | |||
bf2e0f2d73 | |||
e98857fab4 | |||
29b0a352fc | |||
8e4ad10627 | |||
496bc665d6 | |||
2c8531ea48 | |||
b94685e045 | |||
572d602b72 | |||
88051c9302 | |||
d62ee6a611 | |||
91ef4ff30b | |||
4032228005 | |||
50ce13d596 | |||
68302e7c5e | |||
18f9958332 | |||
68231db9a1 | |||
85e849ca00 | |||
617d41c7d5 | |||
cccdced74d | |||
750369b0a6 | |||
539e01deee | |||
4079edc80e | |||
a569990ca2 | |||
9c7eba4431 | |||
513ae9dc10 | |||
effecd4662 | |||
b951cb736a | |||
7e1aed6ad9 | |||
07155e2546 | |||
8c6c8ad3c0 | |||
35f257800e | |||
d0b7c22afc | |||
a18bc15cbb | |||
4ed9cc933f | |||
7af1c86f1c | |||
bd0b7aa230 | |||
72e0938f9a | |||
dd1b0a9380 | |||
4dee913d51 | |||
b764194ed0 | |||
2d0e4ba951 | |||
0d549b687d | |||
738f572043 | |||
cab508fd64 | |||
c7daf697a8 | |||
c20be13733 | |||
b42987059a | |||
82fc7f33a8 | |||
bfa77cf810 | |||
23af170229 | |||
b32d1da421 | |||
6f0362b956 |
.gitignore
.idea/codeStyles
.run
CHANGELOG.mdCMakeLists.txtFSFWVersion.h.inREADME.mdautomation
cmake
FsfwHelpers.cmake
cmake-modules
hal/src/fsfw_hal
scripts
src
CMakeLists.txt
fsfw
CMakeLists.txtFSFWVersion.h.in
action
cfdp
container
controller
coordinates
datalinklayer
datapool
datapoollocal
devicehandlers
events
fdir
globalfunctions
health
housekeeping
internalerror
ipc
memory
modes
monitoring
objectmanager
osal
CMakeLists.txt
common
freertos
CMakeLists.txtFixedTimeslotTask.cppFixedTimeslotTask.hFreeRTOSTaskIF.hPeriodicTask.cppPeriodicTask.h
host
CMakeLists.txtFixedTimeslotTask.cppFixedTimeslotTask.hPeriodicTask.cppPeriodicTask.hTaskFactory.cpptaskHelpers.cpptaskHelpers.h
linux
CMakeLists.txtFixedTimeslotTask.cppFixedTimeslotTask.hPeriodicPosixTask.cppPeriodicPosixTask.hPosixThread.hTaskFactory.cpp
rtems
CMakeLists.txtFixedTimeslotTask.cppFixedTimeslotTask.hMessageQueue.cppMessageQueue.hPeriodicTask.cppPeriodicTask.hQueueFactory.cppRTEMSTaskBase.cppRTEMSTaskBase.hTaskFactory.cpp
windows
parameters
power
CMakeLists.txtDummyPowerSwitcher.cppDummyPowerSwitcher.hFuse.hPowerSwitchIF.hPowerSwitcher.cppPowerSwitcher.hPowerSwitcherComponent.cppPowerSwitcherComponent.hdefinitions.h
pus
CMakeLists.txtCService201HealthCommanding.cppCService201HealthCommanding.hService11TelecommandScheduling.hService11TelecommandScheduling.tppService5EventReporting.cpp
returnvalues
rmap
serialize
serviceinterface
storagemanager
subsystem
tasks
CMakeLists.txtFixedSlotSequence.cppFixedSlotSequence.hFixedTimeslotTaskBase.cppFixedTimeslotTaskBase.hFixedTimeslotTaskIF.hPeriodicTaskBase.cppPeriodicTaskBase.hPeriodicTaskIF.hTaskFactory.hTypedef.hdefinitions.h
tcdistribution
thermal
timemanager
tmstorage
tmtcpacket
tmtcservices
version.cppversion.htests/src/fsfw_tests
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,14 @@
|
|||||||
|
# PyCharm and CLion
|
||||||
|
/.idea/*
|
||||||
|
!/.idea/runConfigurations
|
||||||
|
!/.idea/cmake.xml
|
||||||
|
!/.idea/codeStyles
|
||||||
|
|
||||||
|
# Eclipse
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings
|
||||||
.metadata
|
.metadata
|
||||||
|
|
||||||
/build*
|
/build*
|
||||||
|
/cmake-build*
|
||||||
|
14
.idea/codeStyles/Project.xml
generated
Normal file
14
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<clangFormatSettings>
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</clangFormatSettings>
|
||||||
|
<codeStyleSettings language="CMake">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="0" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
7
.run/fsfw-tests_coverage.run.xml
Normal file
7
.run/fsfw-tests_coverage.run.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="fsfw-tests_coverage" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw-tests_coverage" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
7
.run/fsfw.run.xml
Normal file
7
.run/fsfw.run.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="fsfw" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="fsfw-tests" TARGET_NAME="fsfw" CONFIG_NAME="Debug Unittest" RUN_TARGET_PROJECT_NAME="fsfw-tests" RUN_TARGET_NAME="fsfw-tests">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
118
CHANGELOG.md
118
CHANGELOG.md
@ -12,6 +12,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
- Renamed auto-formatting script to `auto-formatter.sh` and made it more robust.
|
||||||
|
If `cmake-format` is installed, it will also auto-format the `CMakeLists.txt` files now.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/626
|
||||||
|
- Bump C++ required version to C++17. Every project which uses the FSFW and every modern
|
||||||
|
compiler supports it
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/622
|
||||||
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
- HAL Linux SPI: Set the Clock Default State when setting new SPI speed
|
||||||
and mode
|
and mode
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573
|
||||||
@ -22,19 +29,89 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572
|
||||||
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
- HAL Devicehandlers: Periodic printout is run-time configurable now
|
||||||
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
- `oneShotAction` flag in the `TestTask` class is not static anymore
|
||||||
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
- Major update for version handling, using `git describe` to fetch version information with git.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601
|
||||||
|
- Add helper functions provided by [`cmake-modules`](https://github.com/bilke/cmake-modules)
|
||||||
|
manually now. Those should not change too often and only a small subset is needed
|
||||||
|
- Separate folder for easier update and for distinction
|
||||||
|
- LICENSE file included
|
||||||
|
- use `int` for version numbers to allow unset or uninitialized version
|
||||||
|
- Initialize Version object with numbers set to -1
|
||||||
|
- Instead of hardcoding the git hash, it is now retrieved from git
|
||||||
|
- `Version` now allows specifying additional version information like the git SHA1 hash and the
|
||||||
|
versions since the last tag
|
||||||
|
- Additional information is set to the last part of the git describe output for `FSFW_VERSION` now.
|
||||||
|
- Version still need to be hand-updated if the FSFW is not included as a submodule for now.
|
||||||
- IPC Message Queue Handling: Allow passing an optional `MqArgs` argument into the MessageQueue
|
- 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
|
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
|
the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583
|
||||||
- Clock:
|
|
||||||
|
### Task Module Refactoring
|
||||||
|
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/636
|
||||||
|
|
||||||
|
**Refactoring general task code**
|
||||||
|
|
||||||
|
- There was a lot of duplicate/boilerplate code inside the individual task IF OSAL implementations.
|
||||||
|
Remove it by introducing base classes `PeriodicTaskBase` and `FixedTimeslotTaskBase`.
|
||||||
|
|
||||||
|
**Refactor PeriodicTaskIF**
|
||||||
|
|
||||||
|
- Convert `virtual ReturnValue_t addComponent(object_id_t object)` to
|
||||||
|
`virtual ReturnValue_t addComponent(object_id_t object, uint8_t opCode = 0)`, allowing to pass
|
||||||
|
the operation code passed to `performOperation`. Updated API taking
|
||||||
|
an `ExecutableObjectIF` accordingly
|
||||||
|
|
||||||
|
**Refactor FixedTimeslotTaskIF**
|
||||||
|
|
||||||
|
- Add additional `addSlot` function which takes an `ExecutableObjectIF` pointer and its Object ID
|
||||||
|
|
||||||
|
**Refactor FixedSequenceSlot**
|
||||||
|
|
||||||
|
- Introduce typedef `CustomCheckFunc` for `ReturnValue_t (*customCheckFunction)(const SlotList&)`.
|
||||||
|
- Convert `ReturnValue_t (*customCheckFunction)(const SlotList&)` to
|
||||||
|
`ReturnValue_t (*customCheckFunction)(const SlotList&, void*)`, allowing arbitrary user arguments
|
||||||
|
for the custom checker
|
||||||
|
|
||||||
|
**Linux Task Module**
|
||||||
|
|
||||||
|
- Use composition instead of inheritance for the `PeriodicPosixTask` and make the `PosixTask` a
|
||||||
|
member of the class
|
||||||
|
|
||||||
|
### HAL
|
||||||
|
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
- 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
|
||||||
|
- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585
|
||||||
|
|
||||||
|
### Time
|
||||||
|
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and
|
||||||
|
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||||
|
|
||||||
- `timeval` to `TimeOfDay_t`
|
- `timeval` to `TimeOfDay_t`
|
||||||
- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/)
|
- 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
|
- Moved the statics used by Clock in ClockCommon.cpp to this file
|
||||||
- Better check for leap seconds
|
- Better check for leap seconds
|
||||||
- Added Unittests for Clock (only getter)
|
- Added Unittests for Clock (only getter)
|
||||||
|
|
||||||
|
### Power
|
||||||
|
|
||||||
|
- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and
|
||||||
|
also specify a `ReturnValue_t` return type
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or
|
||||||
|
`turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
- Removed the `HkSwitchHelper`. This module should not be needed anymore, now that the local
|
||||||
@ -43,15 +120,50 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Additions
|
## Additions
|
||||||
|
|
||||||
|
- Added options for CI/CD builds: `FSFW_CICD_BUILD`. This allows the source code to know
|
||||||
|
whether it is running in CI/CD
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/623
|
||||||
|
- Basic `clion` support: Update `.gitignore` and add some basic run configurations
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/625
|
||||||
|
- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether
|
||||||
|
the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it,
|
||||||
|
can make good use of it and it usually makes the code faster and/or smaller.
|
||||||
|
After some more research:
|
||||||
|
Enabling LTO will actually cause the compiler to only produce thin LTO by adding
|
||||||
|
`-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice
|
||||||
|
because if an application linking against the FSFW does not use LTO, there can be compile
|
||||||
|
issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as
|
||||||
|
can be seen in the multiple CMake issues for it:
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/22913,
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/16808,
|
||||||
|
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||||
|
Easiest solution for now: Keep this option OFF by default.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
- 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
|
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||||
inside `fsfw/version.h`
|
inside `fsfw/version.h`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||||
|
- Added generic PUS TC Scheduler Service 11. It depends on the new added Emebeded Template Library
|
||||||
|
(ETL) dependency.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/594
|
||||||
- Added ETL dependency and improved library dependency management
|
- Added ETL dependency and improved library dependency management
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592
|
||||||
|
- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- New typedef for switcher type
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||||
|
- `Subsystem`: New API to add table and sequence entries
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||||
|
`TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)` call.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/618
|
||||||
|
- Fix infinite recursion in `prepareHealthSetReply` of PUS Health Service 201.
|
||||||
|
Is not currently used right now but might be used in the future
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/617
|
||||||
|
- Move some CMake directives further up top so they are not ignored
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/621
|
||||||
- Small bugfix in STM32 HAL for SPI
|
- Small bugfix in STM32 HAL for SPI
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/599
|
||||||
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
- HAL GPIO: Improved error checking in `LinuxLibgpioIF::configureGpios(...)`. If a GPIO
|
||||||
|
375
CMakeLists.txt
375
CMakeLists.txt
@ -1,37 +1,111 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(FSFW_VERSION 4)
|
set(MSG_PREFIX "fsfw |")
|
||||||
set(FSFW_SUBVERSION 0)
|
|
||||||
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})
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/bilke")
|
||||||
|
list(APPEND CMAKE_MODULE_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules/rpavlik")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING
|
# ##############################################################################
|
||||||
"ETL library major version requirement"
|
# Version file handling #
|
||||||
)
|
# ##############################################################################
|
||||||
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
|
set(FSFW_VERSION_IF_GIT_FAILS 4)
|
||||||
"Catch2 library major version requirement"
|
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE STRING
|
|
||||||
"Catch2 library exact version requirement"
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
)
|
# Version handling
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
|
||||||
|
message(STATUS "${MSG_PREFIX} Determining version information with git")
|
||||||
|
include(FsfwHelpers)
|
||||||
|
determine_version_with_git("--exclude" "docker_*")
|
||||||
|
if(GIT_INFO)
|
||||||
|
set(FSFW_GIT_INFO
|
||||||
|
${GIT_INFO}
|
||||||
|
CACHE STRING "Version information retrieved with git describe")
|
||||||
|
list(GET FSFW_GIT_INFO 1 FSFW_VERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 2 FSFW_SUBVERSION)
|
||||||
|
list(GET FSFW_GIT_INFO 3 FSFW_REVISION)
|
||||||
|
list(GET FSFW_GIT_INFO 4 FSFW_VCS_INFO)
|
||||||
|
if(NOT FSFW_VERSION)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_SUBVERSION)
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_REVISION)
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK TRUE)
|
||||||
|
else()
|
||||||
|
set(FSFW_GIT_VER_HANDLING_OK FALSE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(NOT FSFW_GIT_VER_HANDLING_OK)
|
||||||
|
set(FSFW_VERSION ${FSFW_VERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_SUBVERSION ${FSFW_SUBVERSION_IF_GIT_FAILS})
|
||||||
|
set(FSFW_REVISION ${FSFW_REVISION_IF_GIT_FAILS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(LIB_FSFW_NAME fsfw)
|
||||||
|
project(${LIB_FSFW_NAME}
|
||||||
|
VERSION ${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION})
|
||||||
|
|
||||||
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_NAME etl)
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
|
set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||||
|
20
|
||||||
|
CACHE STRING "ETL library major version requirement")
|
||||||
|
set(FSFW_ETL_LIB_VERSION
|
||||||
|
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Keep this off by default for now. See PR:
|
||||||
|
# https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 for information which
|
||||||
|
# keeping this on by default is problematic
|
||||||
|
option(
|
||||||
|
FSFW_ENABLE_IPO
|
||||||
|
"Enable interprocedural optimization or link-time optimization if available"
|
||||||
|
OFF)
|
||||||
|
if(FSFW_ENABLE_IPO)
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR)
|
||||||
|
if(NOT IPO_SUPPORTED)
|
||||||
|
message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
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)
|
||||||
)
|
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF)
|
option(FSFW_BUILD_UNITTESTS
|
||||||
|
"Build unittest binary in addition to static library" OFF)
|
||||||
|
option(FSFW_CICD_BUILD "Build for CI/CD. This can disable problematic test" OFF)
|
||||||
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_UNITTESTS)
|
||||||
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
|
||||||
@ -55,72 +129,76 @@ option(FSFW_ADD_TMSTORAGE "Compile with tm storage components" OFF)
|
|||||||
# Contrib sources
|
# Contrib sources
|
||||||
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
|
||||||
|
|
||||||
set(LIB_FSFW_NAME fsfw)
|
|
||||||
set(FSFW_TEST_TGT fsfw-tests)
|
set(FSFW_TEST_TGT fsfw-tests)
|
||||||
set(FSFW_DUMMY_TGT fsfw-dummy)
|
set(FSFW_DUMMY_TGT fsfw-dummy)
|
||||||
|
|
||||||
project(${LIB_FSFW_NAME})
|
|
||||||
add_library(${LIB_FSFW_NAME})
|
add_library(${LIB_FSFW_NAME})
|
||||||
|
|
||||||
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
|
set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION
|
||||||
|
TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_BUILD_UNITTESTS)
|
if(FSFW_BUILD_UNITTESTS)
|
||||||
message(STATUS "Building the FSFW unittests in addition to the static library")
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} 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 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
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")
|
message(
|
||||||
|
STATUS
|
||||||
|
"${MSG_PREFIX} 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 ${FSFW_CATCH2_LIB_VERSION}
|
GIT_TAG ${FSFW_CATCH2_LIB_VERSION})
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS Catch2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
|
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
|
||||||
configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
||||||
configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in tests/TestsConfig.h)
|
configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in
|
||||||
|
tests/TestsConfig.h)
|
||||||
|
|
||||||
project(${FSFW_TEST_TGT} CXX C)
|
project(${FSFW_TEST_TGT} CXX C)
|
||||||
add_executable(${FSFW_TEST_TGT})
|
add_executable(${FSFW_TEST_TGT})
|
||||||
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
|
set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION
|
||||||
|
TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(FSFW_TESTS_GEN_COV)
|
if(FSFW_TESTS_GEN_COV)
|
||||||
message(STATUS "Generating coverage data for the library")
|
message(STATUS "${MSG_PREFIX} Generating coverage data for the library")
|
||||||
message(STATUS "Targets linking against ${LIB_FSFW_NAME} "
|
message(STATUS "${MSG_PREFIX} Targets linking against ${LIB_FSFW_NAME} "
|
||||||
"will be compiled with coverage data as well"
|
"will be compiled with coverage data as well")
|
||||||
)
|
|
||||||
include(FetchContent)
|
|
||||||
FetchContent_Declare(
|
|
||||||
cmake-modules
|
|
||||||
GIT_REPOSITORY https://github.com/bilke/cmake-modules.git
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(cmake-modules)
|
|
||||||
set(CMAKE_BUILD_TYPE "Debug")
|
set(CMAKE_BUILD_TYPE "Debug")
|
||||||
list(APPEND CMAKE_MODULE_PATH ${cmake-modules_SOURCE_DIR})
|
|
||||||
include(CodeCoverage)
|
include(CodeCoverage)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
message(STATUS "Finding and/or providing ETL library")
|
message(STATUS "${MSG_PREFIX} Finding and/or providing ETL library")
|
||||||
|
|
||||||
# Check whether the user has already installed ETL first
|
# Check whether the user has already installed ETL first
|
||||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||||
# Not installed, so use FetchContent to download and provide etl
|
# Not installed, so use FetchContent to download and provide etl
|
||||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||||
message(STATUS
|
message(
|
||||||
|
STATUS
|
||||||
"No ETL installation was found with find_package. Installing and providing "
|
"No ETL installation was found with find_package. Installing and providing "
|
||||||
"etl with FindPackage"
|
"etl with FindPackage")
|
||||||
)
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
${FSFW_ETL_LIB_NAME}
|
${FSFW_ETL_LIB_NAME}
|
||||||
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
GIT_REPOSITORY https://github.com/ETLCPP/etl
|
||||||
GIT_TAG ${FSFW_ETL_LIB_VERSION}
|
GIT_TAG ${FSFW_ETL_LIB_VERSION})
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
list(APPEND FSFW_FETCH_CONTENT_TARGETS ${FSFW_ETL_LIB_NAME})
|
||||||
endif()
|
endif()
|
||||||
@ -134,8 +212,8 @@ if(FSFW_FETCH_CONTENT_TARGETS)
|
|||||||
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
add_library(${FSFW_ETL_LINK_TARGET} ALIAS ${FSFW_ETL_LIB_NAME})
|
||||||
endif()
|
endif()
|
||||||
if(TARGET Catch2)
|
if(TARGET Catch2)
|
||||||
# Fixes regression -preview4, to be confirmed in later releases
|
# Fixes regression -preview4, to be confirmed in later releases Related
|
||||||
# Related GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
# 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()
|
||||||
endif()
|
endif()
|
||||||
@ -145,23 +223,15 @@ 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)
|
||||||
|
|
||||||
# For configure files
|
# For configure files
|
||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
target_include_directories(${LIB_FSFW_NAME}
|
||||||
)
|
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|
||||||
elseif(${CMAKE_CXX_STANDARD} LESS 11)
|
|
||||||
message(FATAL_ERROR "Compiling the FSFW requires a minimum of C++11 support")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Backwards comptability
|
# Backwards comptability
|
||||||
if(OS_FSFW AND NOT FSFW_OSAL)
|
if(OS_FSFW AND NOT FSFW_OSAL)
|
||||||
message(WARNING "Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Please pass the FSFW OSAL as FSFW_OSAL instead of OS_FSFW")
|
||||||
set(FSFW_OSAL OS_FSFW)
|
set(FSFW_OSAL OS_FSFW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -169,16 +239,14 @@ if(NOT FSFW_OSAL)
|
|||||||
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
|
message(STATUS "No OS for FSFW via FSFW_OSAL set. Assuming host OS")
|
||||||
# Assume host OS and autodetermine from OS_FSFW
|
# Assume host OS and autodetermine from OS_FSFW
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
set(FSFW_OSAL "linux"
|
set(FSFW_OSAL
|
||||||
CACHE STRING
|
"linux"
|
||||||
"OS abstraction layer used in the FSFW"
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
)
|
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
set(FSFW_OSAL "host"
|
set(FSFW_OSAL
|
||||||
CACHE STRING "OS abstraction layer used in the FSFW"
|
"host"
|
||||||
)
|
CACHE STRING "OS abstraction layer used in the FSFW")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
set(FSFW_OSAL_DEFINITION FSFW_OSAL_HOST)
|
||||||
@ -192,15 +260,14 @@ elseif(FSFW_OSAL MATCHES linux)
|
|||||||
elseif(FSFW_OSAL MATCHES freertos)
|
elseif(FSFW_OSAL MATCHES freertos)
|
||||||
set(FSFW_OS_NAME "FreeRTOS")
|
set(FSFW_OS_NAME "FreeRTOS")
|
||||||
set(FSFW_OSAL_FREERTOS ON)
|
set(FSFW_OSAL_FREERTOS ON)
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME})
|
||||||
${LIB_OS_NAME}
|
|
||||||
)
|
|
||||||
elseif(FSFW_OSAL STREQUAL rtems)
|
elseif(FSFW_OSAL STREQUAL rtems)
|
||||||
set(FSFW_OS_NAME "RTEMS")
|
set(FSFW_OS_NAME "RTEMS")
|
||||||
set(FSFW_OSAL_RTEMS ON)
|
set(FSFW_OSAL_RTEMS ON)
|
||||||
else()
|
else()
|
||||||
message(WARNING
|
message(
|
||||||
"Invalid operating system for FSFW specified! Setting to host.."
|
WARNING
|
||||||
|
"${MSG_PREFIX} Invalid operating system for FSFW specified! Setting to host.."
|
||||||
)
|
)
|
||||||
set(FSFW_OS_NAME "Host")
|
set(FSFW_OS_NAME "Host")
|
||||||
set(OS_FSFW "host")
|
set(OS_FSFW "host")
|
||||||
@ -209,7 +276,9 @@ endif()
|
|||||||
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
|
||||||
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
|
||||||
|
|
||||||
message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.")
|
message(
|
||||||
|
STATUS "${MSG_PREFIX} Compiling FSFW for the ${FSFW_OS_NAME} operating system"
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
@ -227,95 +296,86 @@ if(FSFW_BUILD_UNITTESTS)
|
|||||||
include(CodeCoverage)
|
include(CodeCoverage)
|
||||||
|
|
||||||
# Remove quotes.
|
# Remove quotes.
|
||||||
separate_arguments(COVERAGE_COMPILER_FLAGS
|
separate_arguments(COVERAGE_COMPILER_FLAGS NATIVE_COMMAND
|
||||||
NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}"
|
"${COVERAGE_COMPILER_FLAGS}")
|
||||||
)
|
|
||||||
|
|
||||||
# Add compile options manually, we don't want coverage for Catch2
|
# Add compile options manually, we don't want coverage for Catch2
|
||||||
target_compile_options(${FSFW_TEST_TGT} PRIVATE
|
target_compile_options(${FSFW_TEST_TGT}
|
||||||
"${COVERAGE_COMPILER_FLAGS}"
|
PRIVATE "${COVERAGE_COMPILER_FLAGS}")
|
||||||
)
|
target_compile_options(${LIB_FSFW_NAME}
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
PRIVATE "${COVERAGE_COMPILER_FLAGS}")
|
||||||
"${COVERAGE_COMPILER_FLAGS}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Exclude directories here
|
# Exclude directories here
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(GCOVR_ADDITIONAL_ARGS
|
set(GCOVR_ADDITIONAL_ARGS "--exclude-throw-branches"
|
||||||
"--exclude-throw-branches"
|
"--exclude-unreachable-branches")
|
||||||
"--exclude-unreachable-branches"
|
set(COVERAGE_EXCLUDES "/c/msys64/mingw64/*" "*/fsfw_hal/*")
|
||||||
)
|
|
||||||
set(COVERAGE_EXCLUDES
|
|
||||||
"/c/msys64/mingw64/*" "*/fsfw_hal/*"
|
|
||||||
)
|
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
set(COVERAGE_EXCLUDES
|
set(COVERAGE_EXCLUDES
|
||||||
"/usr/include/*" "/usr/bin/*" "Catch2/*"
|
"/usr/include/*"
|
||||||
"/usr/local/include/*" "*/fsfw_tests/*"
|
"/usr/bin/*"
|
||||||
"*/catch2-src/*" "*/fsfw_hal/*"
|
"Catch2/*"
|
||||||
)
|
"/usr/local/include/*"
|
||||||
|
"*/fsfw_tests/*"
|
||||||
|
"*/catch2-src/*"
|
||||||
|
"*/fsfw_hal/*")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_options(${FSFW_TEST_TGT} PRIVATE
|
target_link_options(${FSFW_TEST_TGT} PRIVATE -fprofile-arcs
|
||||||
-fprofile-arcs
|
-ftest-coverage)
|
||||||
-ftest-coverage
|
target_link_options(${LIB_FSFW_NAME} PRIVATE -fprofile-arcs
|
||||||
)
|
-ftest-coverage)
|
||||||
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
# Need to specify this as an interface, otherwise there will the compile
|
||||||
-fprofile-arcs
|
# issues
|
||||||
-ftest-coverage
|
target_link_options(${LIB_FSFW_NAME} INTERFACE -fprofile-arcs
|
||||||
)
|
-ftest-coverage)
|
||||||
# Need to specify this as an interface, otherwise there will the compile issues
|
|
||||||
target_link_options(${LIB_FSFW_NAME} INTERFACE
|
|
||||||
-fprofile-arcs
|
|
||||||
-ftest-coverage
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
setup_target_for_coverage_gcovr_html(
|
setup_target_for_coverage_gcovr_html(
|
||||||
NAME ${FSFW_TEST_TGT}_coverage
|
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||||
EXECUTABLE ${FSFW_TEST_TGT}
|
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||||
DEPENDENCIES ${FSFW_TEST_TGT}
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
setup_target_for_coverage_lcov(
|
setup_target_for_coverage_lcov(
|
||||||
NAME ${FSFW_TEST_TGT}_coverage
|
NAME ${FSFW_TEST_TGT}_coverage EXECUTABLE ${FSFW_TEST_TGT}
|
||||||
EXECUTABLE ${FSFW_TEST_TGT}
|
DEPENDENCIES ${FSFW_TEST_TGT})
|
||||||
DEPENDENCIES ${FSFW_TEST_TGT}
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME})
|
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
|
||||||
|
${LIB_FSFW_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
|
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If
|
||||||
# If this is not given, we include the default configuration and emit a warning.
|
# this is not given, we include the default configuration and emit a warning.
|
||||||
if(NOT FSFW_CONFIG_PATH)
|
if(NOT FSFW_CONFIG_PATH)
|
||||||
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
|
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
|
||||||
if(NOT FSFW_BUILD_DOCS)
|
if(NOT FSFW_BUILD_DOCS)
|
||||||
message(WARNING "Flight Software Framework configuration path not set!")
|
message(
|
||||||
message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..")
|
WARNING
|
||||||
|
"${MSG_PREFIX} Flight Software Framework configuration path not set")
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} Setting default configuration from ${DEF_CONF_PATH} ..")
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(${DEF_CONF_PATH})
|
add_subdirectory(${DEF_CONF_PATH})
|
||||||
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
|
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# FSFW might be part of a possibly complicated folder structure, so we
|
# FSFW might be part of a possibly complicated folder structure, so we extract
|
||||||
# extract the absolute path of the fsfwconfig folder.
|
# the absolute path of the fsfwconfig folder.
|
||||||
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
|
if(IS_ABSOLUTE ${FSFW_CONFIG_PATH})
|
||||||
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
|
set(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH})
|
||||||
else()
|
else()
|
||||||
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE
|
get_filename_component(FSFW_CONFIG_PATH_ABSOLUTE ${FSFW_CONFIG_PATH} REALPATH
|
||||||
${FSFW_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}
|
BASE_DIR ${CMAKE_SOURCE_DIR})
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
|
foreach(INCLUDE_PATH ${FSFW_ADDITIONAL_INC_PATHS})
|
||||||
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
if(IS_ABSOLUTE ${INCLUDE_PATH})
|
||||||
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
|
set(CURR_ABS_INC_PATH "${INCLUDE_PATH}")
|
||||||
else()
|
else()
|
||||||
get_filename_component(CURR_ABS_INC_PATH
|
get_filename_component(CURR_ABS_INC_PATH ${INCLUDE_PATH} REALPATH BASE_DIR
|
||||||
${INCLUDE_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR})
|
${CMAKE_SOURCE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_VERBOSE)
|
if(CMAKE_VERBOSE)
|
||||||
@ -348,23 +408,19 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
-Wcast-qual # Warn if the constness is cast away
|
-Wcast-qual # Warn if the constness is cast away
|
||||||
-Wstringop-overflow=4
|
-Wstringop-overflow=4
|
||||||
# -Wstack-protector # Emits a few false positives for low level access
|
# -Wstack-protector # Emits a few false positives for low level access
|
||||||
# -Wconversion # Creates many false positives
|
# -Wconversion # Creates many false positives -Warith-conversion # Use
|
||||||
# -Warith-conversion # Use with Wconversion to find more implicit conversions
|
# with Wconversion to find more implicit conversions -fanalyzer # Should
|
||||||
# -fanalyzer # Should be used to look through problems
|
# be used to look through problems
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FSFW_GENERATE_SECTIONS)
|
if(FSFW_GENERATE_SECTIONS)
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE "-ffunction-sections"
|
||||||
"-ffunction-sections"
|
"-fdata-sections")
|
||||||
"-fdata-sections"
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FSFW_REMOVE_UNUSED_CODE)
|
if(FSFW_REMOVE_UNUSED_CODE)
|
||||||
target_link_options(${LIB_FSFW_NAME} PRIVATE
|
target_link_options(${LIB_FSFW_NAME} PRIVATE "Wl,--gc-sections")
|
||||||
"Wl,--gc-sections"
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
if(FSFW_WARNING_SHADOW_LOCAL_GCC)
|
||||||
@ -378,42 +434,31 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Required include paths to compile the FSFW
|
# Required include paths to compile the FSFW
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
target_include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${LIB_FSFW_NAME} INTERFACE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
|
||||||
${FSFW_CORE_INC_PATH}
|
|
||||||
${FSFW_ADD_INC_PATHS_ABS}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Includes path required to compile FSFW itself as well
|
# Includes path required to compile FSFW itself as well We assume that the
|
||||||
# We assume that the fsfwconfig folder uses include relative to the project
|
# fsfwconfig folder uses include relative to the project root here!
|
||||||
# root here!
|
target_include_directories(
|
||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
${LIB_FSFW_NAME} PRIVATE ${CMAKE_SOURCE_DIR} ${FSFW_CONFIG_PATH_ABSOLUTE}
|
||||||
${CMAKE_SOURCE_DIR}
|
${FSFW_CORE_INC_PATH} ${FSFW_ADD_INC_PATHS_ABS})
|
||||||
${FSFW_CONFIG_PATH_ABSOLUTE}
|
|
||||||
${FSFW_CORE_INC_PATH}
|
|
||||||
${FSFW_ADD_INC_PATHS_ABS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_options(${LIB_FSFW_NAME} PRIVATE
|
target_compile_options(${LIB_FSFW_NAME} PRIVATE ${FSFW_WARNING_FLAGS}
|
||||||
${FSFW_WARNING_FLAGS}
|
${COMPILER_FLAGS})
|
||||||
${COMPILER_FLAGS}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${FSFW_ETL_LINK_TARGET}
|
||||||
${FSFW_ETL_LINK_TARGET}
|
${FSFW_ADDITIONAL_LINK_LIBS})
|
||||||
${FSFW_ADDITIONAL_LINK_LIBS}
|
|
||||||
)
|
|
||||||
|
|
||||||
string(CONCAT POST_BUILD_COMMENT
|
string(
|
||||||
|
CONCAT
|
||||||
|
POST_BUILD_COMMENT
|
||||||
"######################################################################\n"
|
"######################################################################\n"
|
||||||
"Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, "
|
"Built FSFW v${FSFW_VERSION}.${FSFW_SUBVERSION}.${FSFW_REVISION}, "
|
||||||
"Target OSAL: ${FSFW_OS_NAME}\n"
|
"Target OSAL: ${FSFW_OS_NAME}\n"
|
||||||
"######################################################################\n"
|
"######################################################################\n")
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET ${LIB_FSFW_NAME}
|
TARGET ${LIB_FSFW_NAME}
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMENT ${POST_BUILD_COMMENT}
|
COMMENT ${POST_BUILD_COMMENT})
|
||||||
)
|
|
||||||
|
0
FSFWVersion.h.in
Normal file
0
FSFWVersion.h.in
Normal file
@ -99,7 +99,7 @@ add and link against the FSFW library in general.
|
|||||||
|
|
||||||
4. Link against the FSFW library
|
4. Link against the FSFW library
|
||||||
|
|
||||||
```cmake
|
```sh
|
||||||
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
target_link_libraries(${YourProjectName} PRIVATE fsfw)
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF
|
|||||||
You can use the following commands inside the `fsfw` folder to set up the build system
|
You can use the following commands inside the `fsfw` folder to set up the build system
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
mkdir build-Unittest && cd build-Unittest
|
mkdir build-tests && cd build-tests
|
||||||
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -12,3 +12,9 @@ RUN git clone https://github.com/catchorg/Catch2.git && \
|
|||||||
git checkout v3.0.0-preview5 && \
|
git checkout v3.0.0-preview5 && \
|
||||||
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
|
||||||
cmake --build build/ --target install
|
cmake --build build/ --target install
|
||||||
|
|
||||||
|
RUN git clone https://github.com/ETLCPP/etl.git && \
|
||||||
|
cd etl && \
|
||||||
|
git checkout 20.28.0 && \
|
||||||
|
cmake -B build . && \
|
||||||
|
cmake --install build/
|
||||||
|
2
automation/Jenkinsfile
vendored
2
automation/Jenkinsfile
vendored
@ -14,7 +14,7 @@ pipeline {
|
|||||||
stage('Configure') {
|
stage('Configure') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR) {
|
||||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
cmake/FsfwHelpers.cmake
Normal file
28
cmake/FsfwHelpers.cmake
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Determines the git version with git describe and returns it by setting
|
||||||
|
# the GIT_INFO list in the parent scope. The list has the following entries
|
||||||
|
# 1. Full version string
|
||||||
|
# 2. Major version
|
||||||
|
# 3. Minor version
|
||||||
|
# 4. Revision
|
||||||
|
# 5. git SHA hash and commits since tag
|
||||||
|
function(determine_version_with_git)
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
git_describe(VERSION ${ARGN})
|
||||||
|
string(FIND ${VERSION} "." VALID_VERSION)
|
||||||
|
if(VALID_VERSION EQUAL -1)
|
||||||
|
message(WARNING "Version string ${VERSION} retrieved with git describe is invalid")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
# Parse the version information into pieces.
|
||||||
|
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" _VERSION_MAJOR "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" _VERSION_MINOR "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _VERSION_PATCH "${VERSION}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+-(.*)" "\\1" VERSION_SHA1 "${VERSION}")
|
||||||
|
set(GIT_INFO ${VERSION})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_MAJOR})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_MINOR})
|
||||||
|
list(APPEND GIT_INFO ${_VERSION_PATCH})
|
||||||
|
list(APPEND GIT_INFO ${VERSION_SHA1})
|
||||||
|
set(GIT_INFO ${GIT_INFO} PARENT_SCOPE)
|
||||||
|
message(STATUS "${MSG_PREFIX} Set git version info into GIT_INFO from the git tag ${VERSION}")
|
||||||
|
endfunction()
|
7
cmake/cmake-modules/README.md
Normal file
7
cmake/cmake-modules/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
The files in the `bilke` folder were manually copy and pasted from the
|
||||||
|
[cmake-modules repository](https://github.com/bilke/cmake-modules). It was decided to do
|
||||||
|
this because only a small subset of its provided functions are needed.
|
||||||
|
|
||||||
|
The files in the `rpavlik` folder were manually copy and pasted from the
|
||||||
|
[cmake-modules repository](https://github.com/rpavlik/cmake-modules). It was decided to do
|
||||||
|
this because only a small subset of its provided functions are needed.
|
719
cmake/cmake-modules/bilke/CodeCoverage.cmake
Normal file
719
cmake/cmake-modules/bilke/CodeCoverage.cmake
Normal file
@ -0,0 +1,719 @@
|
|||||||
|
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software without
|
||||||
|
# specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# CHANGES:
|
||||||
|
#
|
||||||
|
# 2012-01-31, Lars Bilke
|
||||||
|
# - Enable Code Coverage
|
||||||
|
#
|
||||||
|
# 2013-09-17, Joakim Söderberg
|
||||||
|
# - Added support for Clang.
|
||||||
|
# - Some additional usage instructions.
|
||||||
|
#
|
||||||
|
# 2016-02-03, Lars Bilke
|
||||||
|
# - Refactored functions to use named parameters
|
||||||
|
#
|
||||||
|
# 2017-06-02, Lars Bilke
|
||||||
|
# - Merged with modified version from github.com/ufz/ogs
|
||||||
|
#
|
||||||
|
# 2019-05-06, Anatolii Kurotych
|
||||||
|
# - Remove unnecessary --coverage flag
|
||||||
|
#
|
||||||
|
# 2019-12-13, FeRD (Frank Dana)
|
||||||
|
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
|
||||||
|
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
|
||||||
|
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
|
||||||
|
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
|
||||||
|
# - Set lcov basedir with -b argument
|
||||||
|
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
|
||||||
|
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
|
||||||
|
# - Delete output dir, .info file on 'make clean'
|
||||||
|
# - Remove Python detection, since version mismatches will break gcovr
|
||||||
|
# - Minor cleanup (lowercase function names, update examples...)
|
||||||
|
#
|
||||||
|
# 2019-12-19, FeRD (Frank Dana)
|
||||||
|
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
|
||||||
|
#
|
||||||
|
# 2020-01-19, Bob Apthorpe
|
||||||
|
# - Added gfortran support
|
||||||
|
#
|
||||||
|
# 2020-02-17, FeRD (Frank Dana)
|
||||||
|
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
|
||||||
|
# in EXCLUDEs, and remove manual escaping from gcovr targets
|
||||||
|
#
|
||||||
|
# 2021-01-19, Robin Mueller
|
||||||
|
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
|
||||||
|
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
|
||||||
|
# flags to the gcovr command
|
||||||
|
#
|
||||||
|
# 2020-05-04, Mihchael Davis
|
||||||
|
# - Add -fprofile-abs-path to make gcno files contain absolute paths
|
||||||
|
# - Fix BASE_DIRECTORY not working when defined
|
||||||
|
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
|
||||||
|
#
|
||||||
|
# 2021-05-10, Martin Stump
|
||||||
|
# - Check if the generator is multi-config before warning about non-Debug builds
|
||||||
|
#
|
||||||
|
# 2022-02-22, Marko Wehle
|
||||||
|
# - Change gcovr output from -o <filename> for --xml <filename> and --html <filename> output respectively.
|
||||||
|
# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt".
|
||||||
|
#
|
||||||
|
# USAGE:
|
||||||
|
#
|
||||||
|
# 1. Copy this file into your cmake modules path.
|
||||||
|
#
|
||||||
|
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
|
||||||
|
# using a CMake option() to enable it just optionally):
|
||||||
|
# include(CodeCoverage)
|
||||||
|
#
|
||||||
|
# 3. Append necessary compiler flags for all supported source files:
|
||||||
|
# append_coverage_compiler_flags()
|
||||||
|
# Or for specific target:
|
||||||
|
# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME)
|
||||||
|
#
|
||||||
|
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
|
||||||
|
#
|
||||||
|
# 4. If you need to exclude additional directories from the report, specify them
|
||||||
|
# using full paths in the COVERAGE_EXCLUDES variable before calling
|
||||||
|
# setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES
|
||||||
|
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
|
||||||
|
# '/path/to/my/src/dir2/*')
|
||||||
|
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
|
||||||
|
# Example:
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
|
||||||
|
#
|
||||||
|
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
|
||||||
|
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
|
||||||
|
# Example:
|
||||||
|
# set(COVERAGE_EXCLUDES "dir1/*")
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME coverage
|
||||||
|
# EXECUTABLE testrunner
|
||||||
|
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
|
||||||
|
# EXCLUDE "dir2/*")
|
||||||
|
#
|
||||||
|
# 5. Use the functions described below to create a custom make target which
|
||||||
|
# runs your test executable and produces a code coverage report.
|
||||||
|
#
|
||||||
|
# 6. Build a Debug build:
|
||||||
|
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||||
|
# make
|
||||||
|
# make my_coverage_target
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
|
||||||
|
|
||||||
|
# Check prereqs
|
||||||
|
find_program( GCOV_PATH gcov )
|
||||||
|
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||||
|
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||||
|
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||||
|
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||||
|
find_program( CPPFILT_PATH NAMES c++filt )
|
||||||
|
|
||||||
|
if(NOT GCOV_PATH)
|
||||||
|
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||||
|
endif() # NOT GCOV_PATH
|
||||||
|
|
||||||
|
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
|
||||||
|
list(GET LANGUAGES 0 LANG)
|
||||||
|
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||||
|
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
|
||||||
|
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||||
|
endif()
|
||||||
|
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
|
||||||
|
# Do nothing; exit conditional without error if true
|
||||||
|
elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
|
||||||
|
# Do nothing; exit conditional without error if true
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage"
|
||||||
|
CACHE INTERNAL "")
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path)
|
||||||
|
if(HAVE_fprofile_abs_path)
|
||||||
|
set(COVERAGE_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_C_FLAGS_COVERAGE
|
||||||
|
${COVERAGE_COMPILER_FLAGS}
|
||||||
|
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||||
|
""
|
||||||
|
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||||
|
FORCE )
|
||||||
|
mark_as_advanced(
|
||||||
|
CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
CMAKE_CXX_FLAGS_COVERAGE
|
||||||
|
CMAKE_C_FLAGS_COVERAGE
|
||||||
|
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||||
|
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||||
|
|
||||||
|
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG))
|
||||||
|
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||||
|
endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)
|
||||||
|
|
||||||
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
|
||||||
|
link_libraries(gcov)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_lcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_lcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT LCOV_PATH)
|
||||||
|
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||||
|
endif() # NOT LCOV_PATH
|
||||||
|
|
||||||
|
if(NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif() # NOT GENHTML_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(LCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setting up commands which will be run to generate coverage data.
|
||||||
|
# Cleanup lcov
|
||||||
|
set(LCOV_CLEAN_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory .
|
||||||
|
-b ${BASEDIR} --zerocounters
|
||||||
|
)
|
||||||
|
# Create baseline to make sure untouched files show up in the report
|
||||||
|
set(LCOV_BASELINE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
|
||||||
|
${BASEDIR} -o ${Coverage_NAME}.base
|
||||||
|
)
|
||||||
|
# Run tests
|
||||||
|
set(LCOV_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Capturing lcov counters and generating report
|
||||||
|
set(LCOV_CAPTURE_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
|
||||||
|
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
|
||||||
|
)
|
||||||
|
# add baseline counters
|
||||||
|
set(LCOV_BASELINE_COUNT_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
|
||||||
|
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
|
||||||
|
)
|
||||||
|
# filter collected data to final coverage report
|
||||||
|
set(LCOV_FILTER_CMD
|
||||||
|
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
|
||||||
|
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
# Generate HTML output
|
||||||
|
set(LCOV_GEN_HTML_CMD
|
||||||
|
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
|
||||||
|
${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
message(STATUS "Command to clean up lcov: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
|
||||||
|
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create baseline: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to run the tests: ")
|
||||||
|
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to capture counters and generate report: ")
|
||||||
|
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
|
||||||
|
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to add baseline counters: ")
|
||||||
|
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
|
||||||
|
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to filter collected data: ")
|
||||||
|
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
|
||||||
|
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate lcov HTML output: ")
|
||||||
|
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
|
||||||
|
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${LCOV_CLEAN_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_CMD}
|
||||||
|
COMMAND ${LCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${LCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${LCOV_BASELINE_COUNT_CMD}
|
||||||
|
COMMAND ${LCOV_FILTER_CMD}
|
||||||
|
COMMAND ${LCOV_GEN_HTML_CMD}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.base
|
||||||
|
${Coverage_NAME}.capture
|
||||||
|
${Coverage_NAME}.total
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${Coverage_NAME}/index.html
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show where to find the lcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_lcov
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_xml(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_xml)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_XML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_XML_CMD
|
||||||
|
${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr XML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_XML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_XML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${Coverage_NAME}.xml
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
||||||
|
)
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_xml
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_gcovr_html(
|
||||||
|
# NAME ctest_coverage # New target name
|
||||||
|
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES executable_target # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
|
||||||
|
# # to BASE_DIRECTORY, with CMake 3.4+)
|
||||||
|
# )
|
||||||
|
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
|
||||||
|
# GCVOR command.
|
||||||
|
function(setup_target_for_coverage_gcovr_html)
|
||||||
|
|
||||||
|
set(options NONE)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT GCOVR_PATH)
|
||||||
|
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||||
|
endif() # NOT GCOVR_PATH
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(DEFINED Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (CMake 3.4+: Also compute absolute paths)
|
||||||
|
set(GCOVR_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER 3.4)
|
||||||
|
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
|
||||||
|
endif()
|
||||||
|
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
|
||||||
|
|
||||||
|
# Combine excludes to several -e arguments
|
||||||
|
set(GCOVR_EXCLUDE_ARGS "")
|
||||||
|
foreach(EXCLUDE ${GCOVR_EXCLUDES})
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
|
||||||
|
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
# Run tests
|
||||||
|
set(GCOVR_HTML_EXEC_TESTS_CMD
|
||||||
|
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
|
||||||
|
)
|
||||||
|
# Create folder
|
||||||
|
set(GCOVR_HTML_FOLDER_CMD
|
||||||
|
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
|
||||||
|
)
|
||||||
|
# Running gcovr
|
||||||
|
set(GCOVR_HTML_CMD
|
||||||
|
${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
|
||||||
|
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Executed command report")
|
||||||
|
|
||||||
|
message(STATUS "Command to run tests: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to create a folder: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(STATUS "Command to generate gcovr HTML coverage data: ")
|
||||||
|
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
|
||||||
|
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_FOLDER_CMD}
|
||||||
|
COMMAND ${GCOVR_HTML_CMD}
|
||||||
|
|
||||||
|
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Running gcovr to produce HTML code coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Show info where to find the report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ;
|
||||||
|
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_gcovr_html
|
||||||
|
|
||||||
|
# Defines a target for running and collection code coverage information
|
||||||
|
# Builds dependencies, runs the given executable and outputs reports.
|
||||||
|
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||||
|
# the coverage generation will not complete.
|
||||||
|
#
|
||||||
|
# setup_target_for_coverage_fastcov(
|
||||||
|
# NAME testrunner_coverage # New target name
|
||||||
|
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||||
|
# DEPENDENCIES testrunner # Dependencies to build first
|
||||||
|
# BASE_DIRECTORY "../" # Base directory for report
|
||||||
|
# # (defaults to PROJECT_SOURCE_DIR)
|
||||||
|
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
|
||||||
|
# NO_DEMANGLE # Don't demangle C++ symbols
|
||||||
|
# # even if c++filt is found
|
||||||
|
# SKIP_HTML # Don't create html report
|
||||||
|
# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths
|
||||||
|
# )
|
||||||
|
function(setup_target_for_coverage_fastcov)
|
||||||
|
|
||||||
|
set(options NO_DEMANGLE SKIP_HTML)
|
||||||
|
set(oneValueArgs BASE_DIRECTORY NAME)
|
||||||
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD)
|
||||||
|
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT FASTCOV_PATH)
|
||||||
|
message(FATAL_ERROR "fastcov not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH)
|
||||||
|
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
|
||||||
|
if(Coverage_BASE_DIRECTORY)
|
||||||
|
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
|
||||||
|
else()
|
||||||
|
set(BASEDIR ${PROJECT_SOURCE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Collect excludes (Patterns, not paths, for fastcov)
|
||||||
|
set(FASTCOV_EXCLUDES "")
|
||||||
|
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
|
||||||
|
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
|
||||||
|
endforeach()
|
||||||
|
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
|
||||||
|
|
||||||
|
# Conditional arguments
|
||||||
|
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
|
||||||
|
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set up commands which will be run to generate coverage data
|
||||||
|
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
|
||||||
|
|
||||||
|
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--process-gcno
|
||||||
|
--output ${Coverage_NAME}.json
|
||||||
|
--exclude ${FASTCOV_EXCLUDES}
|
||||||
|
--exclude ${FASTCOV_EXCLUDES}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH}
|
||||||
|
-C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
|
||||||
|
if(Coverage_SKIP_HTML)
|
||||||
|
set(FASTCOV_HTML_CMD ";")
|
||||||
|
else()
|
||||||
|
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
|
||||||
|
-o ${Coverage_NAME} ${Coverage_NAME}.info
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(FASTCOV_POST_CMD ";")
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
set(FASTCOV_POST_CMD ${Coverage_POST_CMD})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CODE_COVERAGE_VERBOSE)
|
||||||
|
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
|
||||||
|
|
||||||
|
message(" Running tests:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
|
||||||
|
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Capturing fastcov counters and generating report:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
|
||||||
|
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
|
||||||
|
|
||||||
|
message(" Converting fastcov .json to lcov .info:")
|
||||||
|
string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}")
|
||||||
|
message(" ${FASTCOV_CONVERT_CMD_SPACED}")
|
||||||
|
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
message(" Generating HTML report: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
|
||||||
|
message(" ${FASTCOV_HTML_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
if(Coverage_POST_CMD)
|
||||||
|
message(" Running post command: ")
|
||||||
|
string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}")
|
||||||
|
message(" ${FASTCOV_POST_CMD_SPACED}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Setup target
|
||||||
|
add_custom_target(${Coverage_NAME}
|
||||||
|
|
||||||
|
# Cleanup fastcov
|
||||||
|
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
|
||||||
|
--search-directory ${BASEDIR}
|
||||||
|
--zerocounters
|
||||||
|
|
||||||
|
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
|
||||||
|
COMMAND ${FASTCOV_CAPTURE_CMD}
|
||||||
|
COMMAND ${FASTCOV_CONVERT_CMD}
|
||||||
|
COMMAND ${FASTCOV_HTML_CMD}
|
||||||
|
COMMAND ${FASTCOV_POST_CMD}
|
||||||
|
|
||||||
|
# Set output files as GENERATED (will be removed on 'make clean')
|
||||||
|
BYPRODUCTS
|
||||||
|
${Coverage_NAME}.info
|
||||||
|
${Coverage_NAME}.json
|
||||||
|
${Coverage_NAME}/index.html # report directory
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||||
|
DEPENDS ${Coverage_DEPENDENCIES}
|
||||||
|
VERBATIM # Protect arguments to commands
|
||||||
|
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.")
|
||||||
|
if(NOT Coverage_SKIP_HTML)
|
||||||
|
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
|
||||||
|
endif()
|
||||||
|
# Show where to find the fastcov info report
|
||||||
|
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
|
||||||
|
)
|
||||||
|
|
||||||
|
endfunction() # setup_target_for_coverage_fastcov
|
||||||
|
|
||||||
|
function(append_coverage_compiler_flags)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||||
|
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||||
|
endfunction() # append_coverage_compiler_flags
|
||||||
|
|
||||||
|
# Setup coverage for specific library
|
||||||
|
function(append_coverage_compiler_flags_to_target name)
|
||||||
|
target_compile_options(${name}
|
||||||
|
PRIVATE ${COVERAGE_COMPILER_FLAGS})
|
||||||
|
endfunction()
|
23
cmake/cmake-modules/bilke/LICENSE_1_0.txt
Normal file
23
cmake/cmake-modules/bilke/LICENSE_1_0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
284
cmake/cmake-modules/rpavlik/GetGitRevisionDescription.cmake
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||||
|
else()
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# TODO sanitize
|
||||||
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
|
# (ARGN MATCHES "||") OR
|
||||||
|
# (ARGN MATCHES "\\;"))
|
||||||
|
# message("Please report the following error to the project!")
|
||||||
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright 2009-2012, Iowa State University
|
||||||
|
# Copyright 2011-2015, Contributors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
26
cmake/cmake-modules/rpavlik/LICENSES/BSD-3-Clause.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) <year> <owner>. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSES/BSL-1.0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute, execute,
|
||||||
|
and transmit the Software, and to prepare derivative works of the Software,
|
||||||
|
and to permit third-parties to whom the Software is furnished to do so, all
|
||||||
|
subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer, must
|
||||||
|
be included in all copies of the Software, in whole or in part, and all derivative
|
||||||
|
works of the Software, unless such copies or derivative works are solely in
|
||||||
|
the form of machine-executable object code generated by a source language
|
||||||
|
processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES
|
||||||
|
OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
23
cmake/cmake-modules/rpavlik/LICENSE_1_0.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
@ -20,7 +20,9 @@ LinuxLibgpioIF::~LinuxLibgpioIF() {
|
|||||||
ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
ReturnValue_t LinuxLibgpioIF::addGpios(GpioCookie* gpioCookie) {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
if (gpioCookie == nullptr) {
|
if (gpioCookie == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl;
|
sif::error << "LinuxLibgpioIF::addGpios: Invalid cookie" << std::endl;
|
||||||
|
#endif
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +98,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLabel(gpioId_t gpioId,
|
|||||||
std::string& label = gpioByLabel.label;
|
std::string& label = gpioByLabel.label;
|
||||||
struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str());
|
struct gpiod_chip* chip = gpiod_chip_open_by_label(label.c_str());
|
||||||
if (chip == nullptr) {
|
if (chip == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio "
|
sif::warning << "LinuxLibgpioIF::configureGpioByLabel: Failed to open gpio from gpio "
|
||||||
<< "group with label " << label << ". Gpio ID: " << gpioId << std::endl;
|
<< "group with label " << label << ". Gpio ID: " << gpioId << std::endl;
|
||||||
|
#endif
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
std::string failOutput = "label: " + label;
|
std::string failOutput = "label: " + label;
|
||||||
@ -108,8 +112,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByChip(gpioId_t gpioId, GpiodRegularB
|
|||||||
std::string& chipname = gpioByChip.chipname;
|
std::string& chipname = gpioByChip.chipname;
|
||||||
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str());
|
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname.c_str());
|
||||||
if (chip == nullptr) {
|
if (chip == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname
|
sif::warning << "LinuxLibgpioIF::configureGpioByChip: Failed to open chip " << chipname
|
||||||
<< ". Gpio ID: " << gpioId << std::endl;
|
<< ". Gpio ID: " << gpioId << std::endl;
|
||||||
|
#endif
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
std::string failOutput = "chipname: " + chipname;
|
std::string failOutput = "chipname: " + chipname;
|
||||||
@ -133,8 +139,10 @@ ReturnValue_t LinuxLibgpioIF::configureGpioByLineName(gpioId_t gpioId,
|
|||||||
|
|
||||||
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
|
struct gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
|
||||||
if (chip == nullptr) {
|
if (chip == nullptr) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " << chipname
|
sif::warning << "LinuxLibgpioIF::configureGpioByLineName: Failed to open chip " << chipname
|
||||||
<< ". <Gpio ID: " << gpioId << std::endl;
|
<< ". <Gpio ID: " << gpioId << std::endl;
|
||||||
|
#endif
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
std::string failOutput = "line name: " + lineName;
|
std::string failOutput = "line name: " + lineName;
|
||||||
@ -153,10 +161,12 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
|||||||
lineNum = regularGpio.lineNum;
|
lineNum = regularGpio.lineNum;
|
||||||
lineHandle = gpiod_chip_get_line(chip, lineNum);
|
lineHandle = gpiod_chip_get_line(chip, lineNum);
|
||||||
if (!lineHandle) {
|
if (!lineHandle) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
|
sif::warning << "LinuxLibgpioIF::configureRegularGpio: Failed to open line " << std::endl;
|
||||||
sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum << ", " << failOutput
|
sif::warning << "GPIO ID: " << gpioId << ", line number: " << lineNum << ", " << failOutput
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl;
|
sif::warning << "Check if Linux GPIO configuration has changed. " << std::endl;
|
||||||
|
#endif
|
||||||
gpiod_chip_close(chip);
|
gpiod_chip_close(chip);
|
||||||
return RETURN_FAILED;
|
return RETURN_FAILED;
|
||||||
}
|
}
|
||||||
@ -175,7 +185,9 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" << std::endl;
|
sif::error << "LinuxLibgpioIF::configureGpios: Invalid direction specified" << std::endl;
|
||||||
|
#endif
|
||||||
return GPIO_INVALID_INSTANCE;
|
return GPIO_INVALID_INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +216,9 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
|||||||
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||||
gpioMapIter = gpioMap.find(gpioId);
|
gpioMapIter = gpioMap.find(gpioId);
|
||||||
if (gpioMapIter == gpioMap.end()) {
|
if (gpioMapIter == gpioMap.end()) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl;
|
sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl;
|
||||||
|
#endif
|
||||||
return UNKNOWN_GPIO_ID;
|
return UNKNOWN_GPIO_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
|||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ReturnValue_t result = gpioComIF->pullLow(gpioId);
|
result = gpioComIF->pullLow(gpioId);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#include "stm32h7xx_hal.h"
|
#include "stm32h7xx_hal.h"
|
||||||
#include "stm32h7xx_hal_spi.h"
|
#include "stm32h7xx_hal_spi.h"
|
||||||
|
|
||||||
|
#ifndef STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION
|
||||||
|
#define STM_USE_PERIPHERAL_TX_BUFFER_MPU_PROTECTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
|
enum class TransferStates { IDLE, WAIT, SUCCESS, FAILURE };
|
||||||
|
|
||||||
class GyroL3GD20H {
|
class GyroL3GD20H {
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
if [[ ! -f README.md ]]; then
|
|
||||||
cd ..
|
|
||||||
fi
|
|
||||||
|
|
||||||
find ./src -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
|
|
||||||
find ./hal -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
|
|
||||||
find ./tests -iname *.h -o -iname *.cpp -o -iname *.c | xargs clang-format --style=file -i
|
|
23
scripts/auto-formatter.sh
Executable file
23
scripts/auto-formatter.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if [[ ! -f README.md ]]; then
|
||||||
|
cd ..
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmake_fmt="cmake-format"
|
||||||
|
file_selectors="-iname CMakeLists.txt"
|
||||||
|
if command -v ${cmake_fmt} &> /dev/null; then
|
||||||
|
${cmake_fmt} -i CMakeLists.txt
|
||||||
|
find ./src ${file_selectors} | xargs ${cmake_fmt} -i
|
||||||
|
else
|
||||||
|
echo "No ${cmake_fmt} tool found, not formatting CMake files"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cpp_format="clang-format"
|
||||||
|
file_selectors="-iname *.h -o -iname *.cpp -o -iname *.c -o -iname *.tpp"
|
||||||
|
if command -v ${cpp_format} &> /dev/null; then
|
||||||
|
find ./src ${file_selectors} | xargs ${cpp_format} --style=file -i
|
||||||
|
find ./hal ${file_selectors} | xargs ${cpp_format} --style=file -i
|
||||||
|
find ./tests ${file_selectors} | xargs ${cpp_format} --style=file -i
|
||||||
|
else
|
||||||
|
echo "No ${cpp_format} tool found, not formatting C++/C files"
|
||||||
|
fi
|
@ -1,9 +1,6 @@
|
|||||||
target_include_directories(${LIB_FSFW_NAME} PRIVATE
|
target_include_directories(${LIB_FSFW_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(${LIB_FSFW_NAME} INTERFACE
|
target_include_directories(${LIB_FSFW_NAME}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(fsfw)
|
add_subdirectory(fsfw)
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE version.cpp)
|
||||||
version.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#ifndef FSFW_VERSION_H_
|
#ifndef FSFW_VERSION_H_
|
||||||
#define FSFW_VERSION_H_
|
#define FSFW_VERSION_H_
|
||||||
|
|
||||||
// Versioning is kept in project CMakeLists.txt file
|
// Versioning is managed in project CMakeLists.txt file
|
||||||
#define FSFW_VERSION_MAJOR @FSFW_VERSION@
|
static constexpr int FSFW_VERSION_MAJOR = @FSFW_VERSION@;
|
||||||
#define FSFW_VERSION_MINOR @FSFW_SUBVERSION@
|
static constexpr int FSFW_VERSION_MINOR = @FSFW_SUBVERSION@;
|
||||||
#define FSFW_VERSION_REVISION @FSFW_REVISION@
|
static constexpr int FSFW_VERSION_REVISION = @FSFW_REVISION@;
|
||||||
|
// Also contains CST (Commits since tag) information
|
||||||
|
static const char FSFW_VCS_INFO[] = "@FSFW_VCS_INFO@";
|
||||||
|
|
||||||
#endif /* FSFW_VERSION_H_ */
|
#endif /* FSFW_VERSION_H_ */
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE ActionHelper.cpp ActionMessage.cpp
|
||||||
ActionHelper.cpp
|
CommandActionHelper.cpp SimpleActionHelper.cpp)
|
||||||
ActionMessage.cpp
|
|
||||||
CommandActionHelper.cpp
|
|
||||||
SimpleActionHelper.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE CFDPHandler.cpp CFDPMessage.cpp)
|
||||||
CFDPHandler.cpp
|
|
||||||
CFDPMessage.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(pdu)
|
add_subdirectory(pdu)
|
||||||
add_subdirectory(tlv)
|
add_subdirectory(tlv)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
PduConfig.cpp
|
${LIB_FSFW_NAME}
|
||||||
|
PRIVATE PduConfig.cpp
|
||||||
VarLenField.cpp
|
VarLenField.cpp
|
||||||
HeaderSerializer.cpp
|
HeaderSerializer.cpp
|
||||||
HeaderDeserializer.cpp
|
HeaderDeserializer.cpp
|
||||||
FileDirectiveDeserializer.cpp
|
FileDirectiveDeserializer.cpp
|
||||||
FileDirectiveSerializer.cpp
|
FileDirectiveSerializer.cpp
|
||||||
|
|
||||||
AckInfo.cpp
|
AckInfo.cpp
|
||||||
AckPduSerializer.cpp
|
AckPduSerializer.cpp
|
||||||
AckPduDeserializer.cpp
|
AckPduDeserializer.cpp
|
||||||
@ -25,8 +25,6 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
|||||||
KeepAlivePduDeserializer.cpp
|
KeepAlivePduDeserializer.cpp
|
||||||
PromptPduSerializer.cpp
|
PromptPduSerializer.cpp
|
||||||
PromptPduDeserializer.cpp
|
PromptPduDeserializer.cpp
|
||||||
|
|
||||||
FileDataSerializer.cpp
|
FileDataSerializer.cpp
|
||||||
FileDataDeserializer.cpp
|
FileDataDeserializer.cpp
|
||||||
FileDataInfo.cpp
|
FileDataInfo.cpp)
|
||||||
)
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
EntityIdTlv.cpp
|
${LIB_FSFW_NAME}
|
||||||
|
PRIVATE EntityIdTlv.cpp
|
||||||
FilestoreRequestTlv.cpp
|
FilestoreRequestTlv.cpp
|
||||||
FilestoreResponseTlv.cpp
|
FilestoreResponseTlv.cpp
|
||||||
Lv.cpp
|
Lv.cpp
|
||||||
Tlv.cpp
|
Tlv.cpp
|
||||||
FlowLabelTlv.cpp
|
FlowLabelTlv.cpp
|
||||||
MessageToUserTlv.cpp
|
MessageToUserTlv.cpp
|
||||||
FaultHandlerOverrideTlv.cpp
|
FaultHandlerOverrideTlv.cpp)
|
||||||
)
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE SharedRingBuffer.cpp
|
||||||
PRIVATE
|
SimpleRingBuffer.cpp)
|
||||||
SharedRingBuffer.cpp
|
|
||||||
SimpleRingBuffer.cpp
|
|
||||||
)
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
|
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity)
|
||||||
maxCapacity(maxCapacity), values(values){};
|
: maxCapacity(maxCapacity), values(values){};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t FIFOBase<T>::insert(T value) {
|
inline ReturnValue_t FIFOBase<T>::insert(T value) {
|
||||||
@ -84,7 +84,6 @@ inline size_t FIFOBase<T>::getMaxCapacity() const {
|
|||||||
return maxCapacity;
|
return maxCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void FIFOBase<T>::setContainer(T* data) {
|
inline void FIFOBase<T>::setContainer(T* data) {
|
||||||
this->values = data;
|
this->values = data;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define FIXEDARRAYLIST_H_
|
#define FIXEDARRAYLIST_H_
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "ArrayList.h"
|
#include "ArrayList.h"
|
||||||
/**
|
/**
|
||||||
@ -9,10 +10,9 @@
|
|||||||
*/
|
*/
|
||||||
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||||
class FixedArrayList : public ArrayList<T, count_t> {
|
class FixedArrayList : public ArrayList<T, count_t> {
|
||||||
#if !defined(_MSC_VER) && !defined(__clang__)
|
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||||
static_assert(MAX_SIZE <= (std::pow(2, sizeof(count_t) * 8) - 1),
|
|
||||||
"count_t is not large enough to hold MAX_SIZE");
|
"count_t is not large enough to hold MAX_SIZE");
|
||||||
#endif
|
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
#ifndef FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
||||||
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
#define FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_
|
||||||
|
|
||||||
|
|
||||||
template <typename key_t, typename T, typename KEY_COMPARE>
|
template <typename key_t, typename T, typename KEY_COMPARE>
|
||||||
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) {
|
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value,
|
||||||
|
Iterator *storedValue) {
|
||||||
if (_size == theMap.maxSize()) {
|
if (_size == theMap.maxSize()) {
|
||||||
return MAP_FULL;
|
return MAP_FULL;
|
||||||
}
|
}
|
||||||
@ -71,7 +71,8 @@ inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename key_t, typename T, typename KEY_COMPARE>
|
template <typename key_t, typename T, typename KEY_COMPARE>
|
||||||
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const {
|
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key,
|
||||||
|
size_t startAt) const {
|
||||||
if (startAt >= _size) {
|
if (startAt >= _size) {
|
||||||
return startAt + 1;
|
return startAt + 1;
|
||||||
}
|
}
|
||||||
@ -105,5 +106,4 @@ inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size
|
|||||||
--_size;
|
--_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */
|
#endif /* FRAMEWORK_CONTAINER_FIXEDORDEREDMULTIMAP_TPP_ */
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE ControllerBase.cpp
|
||||||
ControllerBase.cpp
|
ExtendedControllerBase.cpp)
|
||||||
ExtendedControllerBase.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE CoordinateTransformations.cpp
|
||||||
PRIVATE
|
Sgp4Propagator.cpp)
|
||||||
CoordinateTransformations.cpp
|
|
||||||
Sgp4Propagator.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
Clcw.cpp
|
PRIVATE Clcw.cpp
|
||||||
DataLinkLayer.cpp
|
DataLinkLayer.cpp
|
||||||
Farm1StateLockout.cpp
|
Farm1StateLockout.cpp
|
||||||
Farm1StateOpen.cpp
|
Farm1StateOpen.cpp
|
||||||
@ -8,5 +8,4 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
MapPacketExtraction.cpp
|
MapPacketExtraction.cpp
|
||||||
TcTransferFrame.cpp
|
TcTransferFrame.cpp
|
||||||
TcTransferFrameLocal.cpp
|
TcTransferFrameLocal.cpp
|
||||||
VirtualChannelReception.cpp
|
VirtualChannelReception.cpp)
|
||||||
)
|
|
||||||
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE PoolDataSetBase.cpp PoolEntry.cpp)
|
||||||
PoolDataSetBase.cpp
|
|
||||||
PoolEntry.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
LocalDataPoolManager.cpp
|
PRIVATE LocalDataPoolManager.cpp LocalDataSet.cpp LocalPoolDataSetBase.cpp
|
||||||
LocalDataSet.cpp
|
LocalPoolObjectBase.cpp SharedLocalDataSet.cpp)
|
||||||
LocalPoolDataSetBase.cpp
|
|
||||||
LocalPoolObjectBase.cpp
|
|
||||||
SharedLocalDataSet.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(internal)
|
add_subdirectory(internal)
|
@ -696,9 +696,9 @@ void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
|||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
/* Configuration error */
|
/* Configuration error */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalDataPoolManager::performHkOperation: HK generation failed." << std::endl;
|
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed." << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalDataPoolManager::performHkOperation: HK generation failed.\n");
|
sif::printWarning("LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,26 +6,24 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner,
|
inline LocalPoolVariable<T>::LocalPoolVariable(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
|
||||||
lp_id_t poolId, DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
|
DataSetIF* dataSet, pool_rwm_t setReadWriteMode)
|
||||||
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
|
: LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner,
|
inline LocalPoolVariable<T>::LocalPoolVariable(object_id_t poolOwner, lp_id_t poolId,
|
||||||
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
|
DataSetIF* dataSet, pool_rwm_t setReadWriteMode)
|
||||||
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
|
: LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId,
|
inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId, DataSetIF* dataSet,
|
||||||
DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
|
pool_rwm_t setReadWriteMode)
|
||||||
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
|
: LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet,
|
||||||
dataSet, setReadWriteMode){}
|
setReadWriteMode) {}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::read(
|
inline ReturnValue_t LocalPoolVariable<T>::read(MutexIF::TimeoutType timeoutType,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
uint32_t timeoutMs) {
|
||||||
if (hkManager == nullptr) {
|
if (hkManager == nullptr) {
|
||||||
return readWithoutLock();
|
return readWithoutLock();
|
||||||
}
|
}
|
||||||
@ -43,19 +41,17 @@ template<typename T>
|
|||||||
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
|
inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
|
||||||
if (readWriteMode == pool_rwm_t::VAR_WRITE) {
|
if (readWriteMode == pool_rwm_t::VAR_WRITE) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector",
|
reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true,
|
||||||
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
|
targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolEntry<T>* poolEntry = nullptr;
|
PoolEntry<T>* poolEntry = nullptr;
|
||||||
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
|
ReturnValue_t result =
|
||||||
&poolEntry);
|
LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
|
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVariable", result,
|
reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId);
|
||||||
false, ownerObjectId, localPoolId);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +61,15 @@ inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid,
|
inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid, MutexIF::TimeoutType timeoutType,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
uint32_t timeoutMs) {
|
||||||
this->setValid(setValid);
|
this->setValid(setValid);
|
||||||
return commit(timeoutType, timeoutMs);
|
return commit(timeoutType, timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::commit(
|
inline ReturnValue_t LocalPoolVariable<T>::commit(MutexIF::TimeoutType timeoutType,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
uint32_t timeoutMs) {
|
||||||
if (hkManager == nullptr) {
|
if (hkManager == nullptr) {
|
||||||
return commitWithoutLock();
|
return commitWithoutLock();
|
||||||
}
|
}
|
||||||
@ -91,19 +87,17 @@ template<typename T>
|
|||||||
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
|
inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
|
||||||
if (readWriteMode == pool_rwm_t::VAR_READ) {
|
if (readWriteMode == pool_rwm_t::VAR_READ) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector",
|
reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false,
|
||||||
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
|
targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolEntry<T>* poolEntry = nullptr;
|
PoolEntry<T>* poolEntry = nullptr;
|
||||||
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
|
ReturnValue_t result =
|
||||||
&poolEntry);
|
LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
|
object_id_t ownerObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVariable", result,
|
reportReadCommitError("LocalPoolVariable", result, false, ownerObjectId, localPoolId);
|
||||||
false, ownerObjectId, localPoolId);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,11 +107,10 @@ inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::serialize(uint8_t** buffer,
|
inline ReturnValue_t LocalPoolVariable<T>::serialize(
|
||||||
size_t* size, const size_t max_size,
|
uint8_t** buffer, size_t* size, const size_t max_size,
|
||||||
SerializeIF::Endianness streamEndianness) const {
|
SerializeIF::Endianness streamEndianness) const {
|
||||||
return SerializeAdapter::serialize(&value,
|
return SerializeAdapter::serialize(&value, buffer, size, max_size, streamEndianness);
|
||||||
buffer, size ,max_size, streamEndianness);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -126,15 +119,14 @@ inline size_t LocalPoolVariable<T>::getSerializedSize() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer,
|
inline ReturnValue_t LocalPoolVariable<T>::deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
size_t* size, SerializeIF::Endianness streamEndianness) {
|
SerializeIF::Endianness streamEndianness) {
|
||||||
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
|
return SerializeAdapter::deSerialize(&value, buffer, size, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline std::ostream& operator<< (std::ostream &out,
|
inline std::ostream& operator<<(std::ostream& out, const LocalPoolVariable<T>& var) {
|
||||||
const LocalPoolVariable<T> &var) {
|
|
||||||
out << var.value;
|
out << var.value;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -146,8 +138,7 @@ inline LocalPoolVariable<T>::operator T() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline LocalPoolVariable<T> & LocalPoolVariable<T>::operator=(
|
inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator=(const T& newValue) {
|
||||||
const T& newValue) {
|
|
||||||
value = newValue;
|
value = newValue;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -160,8 +151,7 @@ inline LocalPoolVariable<T>& LocalPoolVariable<T>::operator =(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool LocalPoolVariable<T>::operator ==(
|
inline bool LocalPoolVariable<T>::operator==(const LocalPoolVariable<T>& other) const {
|
||||||
const LocalPoolVariable<T> &other) const {
|
|
||||||
return this->value == other.value;
|
return this->value == other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,10 +160,8 @@ inline bool LocalPoolVariable<T>::operator ==(const T &other) const {
|
|||||||
return this->value == other;
|
return this->value == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool LocalPoolVariable<T>::operator !=(
|
inline bool LocalPoolVariable<T>::operator!=(const LocalPoolVariable<T>& other) const {
|
||||||
const LocalPoolVariable<T> &other) const {
|
|
||||||
return not(*this == other);
|
return not(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,10 +170,8 @@ inline bool LocalPoolVariable<T>::operator !=(const T &other) const {
|
|||||||
return not(*this == other);
|
return not(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool LocalPoolVariable<T>::operator <(
|
inline bool LocalPoolVariable<T>::operator<(const LocalPoolVariable<T>& other) const {
|
||||||
const LocalPoolVariable<T> &other) const {
|
|
||||||
return this->value < other.value;
|
return this->value < other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +180,8 @@ inline bool LocalPoolVariable<T>::operator <(const T &other) const {
|
|||||||
return this->value < other;
|
return this->value < other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool LocalPoolVariable<T>::operator >(
|
inline bool LocalPoolVariable<T>::operator>(const LocalPoolVariable<T>& other) const {
|
||||||
const LocalPoolVariable<T> &other) const {
|
|
||||||
return not(*this < other);
|
return not(*this < other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,25 +6,26 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(
|
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(HasLocalDataPoolIF* hkOwner, lp_id_t poolId,
|
||||||
HasLocalDataPoolIF* hkOwner, lp_id_t poolId, DataSetIF* dataSet,
|
DataSetIF* dataSet,
|
||||||
pool_rwm_t setReadWriteMode):
|
pool_rwm_t setReadWriteMode)
|
||||||
LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
|
: LocalPoolObjectBase(poolId, hkOwner, dataSet, setReadWriteMode) {}
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner,
|
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner, lp_id_t poolId,
|
||||||
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
|
DataSetIF* dataSet,
|
||||||
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
|
pool_rwm_t setReadWriteMode)
|
||||||
|
: LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
|
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet,
|
||||||
DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
|
pool_rwm_t setReadWriteMode)
|
||||||
LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId,
|
: LocalPoolObjectBase(globalPoolId.objectId, globalPoolId.localPoolId, dataSet,
|
||||||
dataSet, setReadWriteMode) {}
|
setReadWriteMode) {}
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::read(MutexIF::TimeoutType timeoutType,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
uint32_t timeoutMs) {
|
||||||
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
||||||
return readWithoutLock();
|
return readWithoutLock();
|
||||||
}
|
}
|
||||||
@ -32,21 +33,19 @@ template<typename T, uint16_t vectorSize>
|
|||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
|
||||||
if (readWriteMode == pool_rwm_t::VAR_WRITE) {
|
if (readWriteMode == pool_rwm_t::VAR_WRITE) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector",
|
reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, true,
|
||||||
PoolVariableIF::INVALID_READ_WRITE_MODE, true, targetObjectId,
|
targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolEntry<T>* poolEntry = nullptr;
|
PoolEntry<T>* poolEntry = nullptr;
|
||||||
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
|
ReturnValue_t result =
|
||||||
&poolEntry);
|
LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
|
||||||
memset(this->value, 0, vectorSize * sizeof(T));
|
memset(this->value, 0, vectorSize * sizeof(T));
|
||||||
|
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector", result, true, targetObjectId,
|
reportReadCommitError("LocalPoolVector", result, true, targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
|
std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
|
||||||
@ -56,14 +55,15 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::readWithoutLock() {
|
|||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(bool valid,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
MutexIF::TimeoutType timeoutType,
|
||||||
|
uint32_t timeoutMs) {
|
||||||
this->setValid(valid);
|
this->setValid(valid);
|
||||||
return commit(timeoutType, timeoutMs);
|
return commit(timeoutType, timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commit(MutexIF::TimeoutType timeoutType,
|
||||||
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
uint32_t timeoutMs) {
|
||||||
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
MutexGuard(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs);
|
||||||
return commitWithoutLock();
|
return commitWithoutLock();
|
||||||
}
|
}
|
||||||
@ -72,18 +72,16 @@ template<typename T, uint16_t vectorSize>
|
|||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::commitWithoutLock() {
|
||||||
if (readWriteMode == pool_rwm_t::VAR_READ) {
|
if (readWriteMode == pool_rwm_t::VAR_READ) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector",
|
reportReadCommitError("LocalPoolVector", PoolVariableIF::INVALID_READ_WRITE_MODE, false,
|
||||||
PoolVariableIF::INVALID_READ_WRITE_MODE, false, targetObjectId,
|
targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
return PoolVariableIF::INVALID_READ_WRITE_MODE;
|
||||||
}
|
}
|
||||||
PoolEntry<T>* poolEntry = nullptr;
|
PoolEntry<T>* poolEntry = nullptr;
|
||||||
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
|
ReturnValue_t result =
|
||||||
&poolEntry);
|
LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, &poolEntry);
|
||||||
if (result != RETURN_OK) {
|
if (result != RETURN_OK) {
|
||||||
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
object_id_t targetObjectId = hkManager->getCreatorObjectId();
|
||||||
reportReadCommitError("LocalPoolVector", result, false, targetObjectId,
|
reportReadCommitError("LocalPoolVector", result, false, targetObjectId, localPoolId);
|
||||||
localPoolId);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
|
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
|
||||||
@ -100,9 +98,11 @@ inline T& LocalPoolVector<T, vectorSize>::operator [](size_t i) {
|
|||||||
// a configuration error, but I wont exit here.
|
// a configuration error, but I wont exit here.
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
||||||
" last value!" << std::endl;
|
" last value!"
|
||||||
|
<< std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
|
sif::printWarning(
|
||||||
|
"LocalPoolVector: Invalid index. Setting or returning"
|
||||||
" last value!\n");
|
" last value!\n");
|
||||||
#endif
|
#endif
|
||||||
return value[vectorSize - 1];
|
return value[vectorSize - 1];
|
||||||
@ -117,22 +117,23 @@ inline const T& LocalPoolVector<T, vectorSize>::operator [](size_t i) const {
|
|||||||
// a configuration error, but I wont exit here.
|
// a configuration error, but I wont exit here.
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
sif::warning << "LocalPoolVector: Invalid index. Setting or returning"
|
||||||
" last value!" << std::endl;
|
" last value!"
|
||||||
|
<< std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printWarning("LocalPoolVector: Invalid index. Setting or returning"
|
sif::printWarning(
|
||||||
|
"LocalPoolVector: Invalid index. Setting or returning"
|
||||||
" last value!\n");
|
" last value!\n");
|
||||||
#endif
|
#endif
|
||||||
return value[vectorSize - 1];
|
return value[vectorSize - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(uint8_t** buffer,
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::serialize(
|
||||||
size_t* size, size_t maxSize,
|
uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndianness) const {
|
SerializeIF::Endianness streamEndianness) const {
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
||||||
for (uint16_t i = 0; i < vectorSize; i++) {
|
for (uint16_t i = 0; i < vectorSize; i++) {
|
||||||
result = SerializeAdapter::serialize(&(value[i]), buffer, size,
|
result = SerializeAdapter::serialize(&(value[i]), buffer, size, maxSize, streamEndianness);
|
||||||
maxSize, streamEndianness);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -147,12 +148,10 @@ inline size_t LocalPoolVector<T, vectorSize>::getSerializedSize() const {
|
|||||||
|
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
|
inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
|
||||||
const uint8_t** buffer, size_t* size,
|
const uint8_t** buffer, size_t* size, SerializeIF::Endianness streamEndianness) {
|
||||||
SerializeIF::Endianness streamEndianness) {
|
|
||||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
|
||||||
for (uint16_t i = 0; i < vectorSize; i++) {
|
for (uint16_t i = 0; i < vectorSize; i++) {
|
||||||
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size,
|
result = SerializeAdapter::deSerialize(&(value[i]), buffer, size, streamEndianness);
|
||||||
streamEndianness);
|
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -162,8 +161,7 @@ inline ReturnValue_t LocalPoolVector<T, vectorSize>::deSerialize(
|
|||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
template <typename T, uint16_t vectorSize>
|
template <typename T, uint16_t vectorSize>
|
||||||
inline std::ostream& operator<< (std::ostream &out,
|
inline std::ostream& operator<<(std::ostream& out, const LocalPoolVector<T, vectorSize>& var) {
|
||||||
const LocalPoolVector<T, vectorSize> &var) {
|
|
||||||
out << "Vector: [";
|
out << "Vector: [";
|
||||||
for (int i = 0; i < vectorSize; i++) {
|
for (int i = 0; i < vectorSize; i++) {
|
||||||
out << var.value[i];
|
out << var.value[i];
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HasLocalDpIFUserAttorney.cpp
|
||||||
PRIVATE
|
HasLocalDpIFManagerAttorney.cpp)
|
||||||
HasLocalDpIFUserAttorney.cpp
|
|
||||||
HasLocalDpIFManagerAttorney.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
AssemblyBase.cpp
|
PRIVATE AssemblyBase.cpp
|
||||||
ChildHandlerBase.cpp
|
ChildHandlerBase.cpp
|
||||||
ChildHandlerFDIR.cpp
|
ChildHandlerFDIR.cpp
|
||||||
DeviceHandlerBase.cpp
|
DeviceHandlerBase.cpp
|
||||||
DeviceHandlerFailureIsolation.cpp
|
DeviceHandlerFailureIsolation.cpp
|
||||||
DeviceHandlerMessage.cpp
|
DeviceHandlerMessage.cpp
|
||||||
DeviceTmReportingWrapper.cpp
|
DeviceTmReportingWrapper.cpp
|
||||||
HealthDevice.cpp
|
HealthDevice.cpp)
|
||||||
)
|
|
||||||
|
@ -1062,7 +1062,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
/**
|
/**
|
||||||
* Same as triggerEvent, but for forwarding if object is used as proxy.
|
* Same as triggerEvent, but for forwarding if object is used as proxy.
|
||||||
*/
|
*/
|
||||||
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const override;
|
virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
|
||||||
|
uint32_t parameter2 = 0) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if current mode is transitional mode.
|
* Checks if current mode is transitional mode.
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE EventManager.cpp EventMessage.cpp)
|
||||||
EventManager.cpp
|
|
||||||
EventMessage.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(eventmatching)
|
add_subdirectory(eventmatching)
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE EventIdRangeMatcher.cpp EventMatchTree.cpp
|
||||||
EventIdRangeMatcher.cpp
|
ReporterRangeMatcher.cpp SeverityRangeMatcher.cpp)
|
||||||
EventMatchTree.cpp
|
|
||||||
ReporterRangeMatcher.cpp
|
|
||||||
SeverityRangeMatcher.cpp
|
|
||||||
)
|
|
||||||
|
@ -27,6 +27,7 @@ enum : uint8_t {
|
|||||||
PUS_SERVICE_6 = 86,
|
PUS_SERVICE_6 = 86,
|
||||||
PUS_SERVICE_8 = 88,
|
PUS_SERVICE_8 = 88,
|
||||||
PUS_SERVICE_9 = 89,
|
PUS_SERVICE_9 = 89,
|
||||||
|
PUS_SERVICE_11 = 91,
|
||||||
PUS_SERVICE_17 = 97,
|
PUS_SERVICE_17 = 97,
|
||||||
PUS_SERVICE_23 = 103,
|
PUS_SERVICE_23 = 103,
|
||||||
MGM_LIS3MDL = 106,
|
MGM_LIS3MDL = 106,
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME} PRIVATE EventCorrelation.cpp FailureIsolationBase.cpp
|
||||||
EventCorrelation.cpp
|
FaultCounter.cpp)
|
||||||
FailureIsolationBase.cpp
|
|
||||||
FaultCounter.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
arrayprinter.cpp
|
PRIVATE arrayprinter.cpp
|
||||||
AsciiConverter.cpp
|
AsciiConverter.cpp
|
||||||
CRC.cpp
|
CRC.cpp
|
||||||
DleEncoder.cpp
|
DleEncoder.cpp
|
||||||
PeriodicOperationDivider.cpp
|
PeriodicOperationDivider.cpp
|
||||||
timevalOperations.cpp
|
timevalOperations.cpp
|
||||||
Type.cpp
|
Type.cpp
|
||||||
bitutility.cpp
|
bitutility.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(math)
|
add_subdirectory(math)
|
||||||
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE QuaternionOperations.cpp)
|
||||||
PRIVATE
|
|
||||||
QuaternionOperations.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,6 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HealthHelper.cpp HealthMessage.cpp
|
||||||
PRIVATE
|
HealthTable.cpp)
|
||||||
HealthHelper.cpp
|
|
||||||
HealthMessage.cpp
|
|
||||||
HealthTable.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE HousekeepingMessage.cpp
|
||||||
PRIVATE
|
PeriodicHousekeepingHelper.cpp)
|
||||||
HousekeepingMessage.cpp
|
|
||||||
PeriodicHousekeepingHelper.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,4 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE InternalErrorReporter.cpp)
|
||||||
PRIVATE
|
|
||||||
InternalErrorReporter.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
CommandMessage.cpp
|
${LIB_FSFW_NAME} PRIVATE CommandMessage.cpp CommandMessageCleaner.cpp
|
||||||
CommandMessageCleaner.cpp
|
MessageQueueMessage.cpp MessageQueueBase.cpp)
|
||||||
MessageQueueMessage.cpp
|
|
||||||
MessageQueueBase.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE MemoryHelper.cpp MemoryMessage.cpp
|
||||||
MemoryHelper.cpp
|
GenericFileSystemMessage.cpp)
|
||||||
MemoryMessage.cpp
|
|
||||||
GenericFileSystemMessage.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE ModeHelper.cpp ModeMessage.cpp)
|
||||||
PRIVATE
|
|
||||||
ModeHelper.cpp
|
|
||||||
ModeMessage.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE LimitViolationReporter.cpp
|
||||||
PRIVATE
|
MonitoringMessage.cpp)
|
||||||
LimitViolationReporter.cpp
|
|
||||||
MonitoringMessage.cpp
|
|
||||||
)
|
|
||||||
|
@ -1,5 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(${LIB_FSFW_NAME} PRIVATE ObjectManager.cpp SystemObject.cpp)
|
||||||
PRIVATE
|
|
||||||
ObjectManager.cpp
|
|
||||||
SystemObject.cpp
|
|
||||||
)
|
|
||||||
|
@ -50,7 +50,8 @@ class SystemObject : public SystemObjectIF {
|
|||||||
virtual ReturnValue_t initialize() override;
|
virtual ReturnValue_t initialize() override;
|
||||||
virtual ReturnValue_t checkObjectConnections() override;
|
virtual ReturnValue_t checkObjectConnections() override;
|
||||||
|
|
||||||
virtual void forwardEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0) const override;
|
virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
|
||||||
|
uint32_t parameter2 = 0) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */
|
#endif /* FSFW_OBJECTMANAGER_SYSTEMOBJECT_H_ */
|
||||||
|
@ -14,6 +14,7 @@ enum framework_objects : object_id_t {
|
|||||||
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
|
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
|
||||||
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
||||||
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
||||||
|
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
|
||||||
PUS_SERVICE_17_TEST = 0x53000017,
|
PUS_SERVICE_17_TEST = 0x53000017,
|
||||||
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
||||||
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
||||||
|
@ -11,9 +11,7 @@ elseif(FSFW_OSAL MATCHES "host")
|
|||||||
add_subdirectory(windows)
|
add_subdirectory(windows)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
# We still need to pull in some Linux specific sources
|
# We still need to pull in some Linux specific sources
|
||||||
target_sources(${LIB_FSFW_NAME} PUBLIC
|
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
|
||||||
linux/tcpipHelpers.cpp
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
else()
|
else()
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
if(DEFINED WIN32 OR DEFINED UNIX)
|
if(DEFINED WIN32 OR DEFINED UNIX)
|
||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
tcpipCommon.cpp
|
${LIB_FSFW_NAME}
|
||||||
TcpIpBase.cpp
|
PRIVATE tcpipCommon.cpp TcpIpBase.cpp UdpTcPollingTask.cpp
|
||||||
UdpTcPollingTask.cpp
|
UdpTmTcBridge.cpp TcpTmTcServer.cpp TcpTmTcBridge.cpp)
|
||||||
UdpTmTcBridge.cpp
|
|
||||||
TcpTmTcServer.cpp
|
|
||||||
TcpTmTcBridge.cpp
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE wsock32 ws2_32)
|
||||||
wsock32
|
|
||||||
ws2_32
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
@ -19,6 +19,8 @@
|
|||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
@ -29,7 +31,7 @@ TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
|||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
tmtcBridgeId(tmtcTcpBridge),
|
tmtcBridgeId(tmtcTcpBridge),
|
||||||
receptionMode(receptionMode),
|
receptionMode(receptionMode),
|
||||||
tcpConfig(customTcpServerPort),
|
tcpConfig(std::move(customTcpServerPort)),
|
||||||
receptionBuffer(receptionBufferSize),
|
receptionBuffer(receptionBufferSize),
|
||||||
ringBuffer(ringBufferSize, true) {}
|
ringBuffer(ringBufferSize, true) {}
|
||||||
|
|
||||||
@ -103,12 +105,12 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
|||||||
|
|
||||||
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
TcpTmTcServer::~TcpTmTcServer() { closeSocket(listenerTcpSocket); }
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
[[noreturn]] ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
||||||
using namespace tcpip;
|
using namespace tcpip;
|
||||||
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
// If a connection is accepted, the corresponding socket will be assigned to the new socket
|
||||||
socket_t connSocket = 0;
|
socket_t connSocket = 0;
|
||||||
// sockaddr clientSockAddr = {};
|
sockaddr clientSockAddr = {};
|
||||||
// socklen_t connectorSockAddrLen = 0;
|
socklen_t connectorSockAddrLen = 0;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
// Listen for connection requests permanently for lifetime of program
|
// Listen for connection requests permanently for lifetime of program
|
||||||
@ -119,8 +121,7 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
connSocket = accept(listenerTcpSocket, &clientSockAddr, &connectorSockAddrLen);
|
||||||
connSocket = accept(listenerTcpSocket, nullptr, nullptr);
|
|
||||||
|
|
||||||
if (connSocket == INVALID_SOCKET) {
|
if (connSocket == INVALID_SOCKET) {
|
||||||
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
||||||
@ -135,10 +136,10 @@ ReturnValue_t TcpTmTcServer::performOperation(uint8_t opCode) {
|
|||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
|
handleError(Protocol::TCP, ErrorSources::SHUTDOWN_CALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeSocket(connSocket);
|
closeSocket(connSocket);
|
||||||
connSocket = 0;
|
connSocket = 0;
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
ReturnValue_t TcpTmTcServer::initializeAfterTaskCreation() {
|
||||||
@ -159,7 +160,7 @@ void TcpTmTcServer::handleServerOperation(socket_t& connSocket) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
ssize_t retval = recv(connSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
receptionBuffer.capacity(), tcpConfig.tcpFlags);
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
size_t availableReadData = ringBuffer.getAvailableReadData();
|
size_t availableReadData = ringBuffer.getAvailableReadData();
|
||||||
@ -252,17 +253,17 @@ ReturnValue_t TcpTmTcServer::handleTcReception(uint8_t* spacePacket, size_t pack
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
const std::string& TcpTmTcServer::getTcpPort() const { return tcpConfig.tcpPort; }
|
||||||
|
|
||||||
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds) {
|
void TcpTmTcServer::setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds_) {
|
||||||
this->validPacketIds = validPacketIds;
|
this->validPacketIds = std::move(validPacketIds_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
TcpTmTcServer::TcpConfig& TcpTmTcServer::getTcpConfigStruct() { return tcpConfig; }
|
||||||
|
|
||||||
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent) {
|
||||||
// Access to the FIFO is mutex protected because it is filled by the bridge
|
// Access to the FIFO is mutex protected because it is filled by the bridge
|
||||||
MutexGuard(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
MutexGuard mg(tmtcBridge->mutex, tmtcBridge->timeoutType, tmtcBridge->mutexTimeoutMs);
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
while ((not tmtcBridge->tmFifo->empty()) and
|
while ((not tmtcBridge->tmFifo->empty()) and
|
||||||
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
(tmtcBridge->packetSentCounter < tmtcBridge->sentPacketsPerCycle)) {
|
||||||
@ -283,7 +284,7 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
|||||||
#endif
|
#endif
|
||||||
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
arrayprinter::print(storeAccessor.data(), storeAccessor.size());
|
||||||
}
|
}
|
||||||
int retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
ssize_t retval = send(connSocket, reinterpret_cast<const char*>(storeAccessor.data()),
|
||||||
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
storeAccessor.size(), tcpConfig.tcpTmFlags);
|
||||||
if (retval == static_cast<int>(storeAccessor.size())) {
|
if (retval == static_cast<int>(storeAccessor.size())) {
|
||||||
// Packet sent, clear FIFO entry
|
// Packet sent, clear FIFO entry
|
||||||
@ -339,6 +340,9 @@ ReturnValue_t TcpTmTcServer::handleTcRingBufferData(size_t availableReadData) {
|
|||||||
size_t foundSize = 0;
|
size_t foundSize = 0;
|
||||||
size_t readLen = 0;
|
size_t readLen = 0;
|
||||||
while (readLen < readAmount) {
|
while (readLen < readAmount) {
|
||||||
|
if (spacePacketParser == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
result =
|
result =
|
||||||
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
spacePacketParser->parseSpacePackets(bufPtrPtr, readAmount, startIdx, foundSize, readLen);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class TcpTmTcBridge;
|
class TcpTmTcBridge;
|
||||||
@ -44,7 +45,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
struct TcpConfig {
|
struct TcpConfig {
|
||||||
public:
|
public:
|
||||||
TcpConfig(std::string tcpPort) : tcpPort(tcpPort) {}
|
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passed to the recv call
|
* Passed to the recv call
|
||||||
@ -84,7 +85,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||||
virtual ~TcpTmTcServer();
|
~TcpTmTcServer() override;
|
||||||
|
|
||||||
void enableWiretapping(bool enable);
|
void enableWiretapping(bool enable);
|
||||||
|
|
||||||
@ -97,10 +98,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
void setSpacePacketParsingOptions(std::vector<uint16_t> validPacketIds);
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
[[noreturn]] ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
std::string getTcpPort() const;
|
[[nodiscard]] const std::string& getTcpPort() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
StorageManagerIF* tcStore = nullptr;
|
StorageManagerIF* tcStore = nullptr;
|
||||||
@ -115,7 +116,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
ReceptionModes receptionMode;
|
ReceptionModes receptionMode;
|
||||||
TcpConfig tcpConfig;
|
TcpConfig tcpConfig;
|
||||||
struct sockaddr tcpAddress;
|
struct sockaddr tcpAddress = {};
|
||||||
socket_t listenerTcpSocket = 0;
|
socket_t listenerTcpSocket = 0;
|
||||||
|
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
@ -29,8 +29,8 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
|||||||
/* The ports chosen here should not be used by any other process. */
|
/* The ports chosen here should not be used by any other process. */
|
||||||
static const std::string DEFAULT_SERVER_PORT;
|
static const std::string DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, const std::string& udpServerPort = "",
|
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
object_id_t tmStoreId = objects::TM_STORE,
|
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
~UdpTmTcBridge() override;
|
~UdpTmTcBridge() override;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
Clock.cpp
|
PRIVATE Clock.cpp
|
||||||
FixedTimeslotTask.cpp
|
FixedTimeslotTask.cpp
|
||||||
BinarySemaphore.cpp
|
BinarySemaphore.cpp
|
||||||
BinSemaphUsingTask.cpp
|
BinSemaphUsingTask.cpp
|
||||||
@ -15,18 +15,16 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
Timekeeper.cpp
|
Timekeeper.cpp
|
||||||
TaskManagement.cpp
|
TaskManagement.cpp
|
||||||
QueueMapManager.cpp
|
QueueMapManager.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
# FreeRTOS is required to link the FSFW now. It is recommended to compile
|
# FreeRTOS is required to link the FSFW now. It is recommended to compile
|
||||||
# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the
|
# FreeRTOS as a static library and set LIB_OS_NAME to the target name of the
|
||||||
# library.
|
# library.
|
||||||
if(NOT LIB_OS_NAME)
|
if(NOT LIB_OS_NAME)
|
||||||
message(STATUS
|
message(
|
||||||
|
STATUS
|
||||||
"LIB_OS_NAME is empty. Make sure to include the FreeRTOS header path properly."
|
"LIB_OS_NAME is empty. Make sure to include the FreeRTOS header path properly."
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${LIB_OS_NAME})
|
||||||
${LIB_OS_NAME}
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,27 +1,23 @@
|
|||||||
#include "fsfw/osal/freertos/FixedTimeslotTask.h"
|
#include "fsfw/osal/freertos/FixedTimeslotTask.h"
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/serviceinterface.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
|
||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
|
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
|
||||||
TaskStackSize setStack, TaskPeriod overallPeriod,
|
TaskStackSize setStack, TaskPeriod period,
|
||||||
void (*setDeadlineMissedFunc)())
|
TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false), handle(nullptr), pst(overallPeriod * 1000) {
|
: FixedTimeslotTaskBase(period, dlmFunc_), started(false), handle(nullptr) {
|
||||||
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
|
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
|
||||||
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
|
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
|
||||||
// All additional attributes are applied to the object.
|
|
||||||
this->deadlineMissedFunc = setDeadlineMissedFunc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask() {}
|
FixedTimeslotTask::~FixedTimeslotTask() = default;
|
||||||
|
|
||||||
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
||||||
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
|
// The argument is re-interpreted as FixedTimeslotTask. The Task object is
|
||||||
// global, so it is found from any place.
|
// global, so it is found from any place.
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
||||||
/* Task should not start until explicitly requested,
|
/* Task should not start until explicitly requested,
|
||||||
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
|
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
|
||||||
* is running but not if the scheduler is not running.
|
* is running but not if the scheduler is not running.
|
||||||
@ -32,26 +28,18 @@ void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
|||||||
* can continue */
|
* can continue */
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
vTaskSuspend(NULL);
|
vTaskSuspend(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality."
|
sif::debug << "Polling task " << originalTask->handle << " returned from taskFunctionality."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
#else
|
||||||
|
sif::printDebug("Polling task returned from taskFunctionality\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
|
||||||
FixedTimeslotTask::deadlineMissedCount++;
|
|
||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||||
started = true;
|
started = true;
|
||||||
|
|
||||||
@ -63,31 +51,12 @@ ReturnValue_t FixedTimeslotTask::startTask() {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF* handler = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (handler != nullptr) {
|
|
||||||
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); }
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); }
|
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
|
||||||
// A local iterator for the Polling Sequence Table is created to find the
|
// A local iterator for the Polling Sequence Table is created to find the
|
||||||
// start time for the first entry.
|
// start time for the first entry.
|
||||||
auto slotListIter = pst.current;
|
auto slotListIter = pollingSeqTable.current;
|
||||||
|
|
||||||
pst.intializeSequenceAfterTaskCreation();
|
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||||
|
|
||||||
// The start time for the first entry is read.
|
// The start time for the first entry is read.
|
||||||
uint32_t intervalMs = slotListIter->pollingTimeMs;
|
uint32_t intervalMs = slotListIter->pollingTimeMs;
|
||||||
@ -108,10 +77,10 @@ void FixedTimeslotTask::taskFunctionality() {
|
|||||||
/* Enter the loop that defines the task behavior. */
|
/* Enter the loop that defines the task behavior. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// The component for this slot is executed and the next one is chosen.
|
// The component for this slot is executed and the next one is chosen.
|
||||||
this->pst.executeAndAdvance();
|
this->pollingSeqTable.executeAndAdvance();
|
||||||
if (not pst.slotFollowsImmediately()) {
|
if (not pollingSeqTable.slotFollowsImmediately()) {
|
||||||
// Get the interval till execution of the next slot.
|
// Get the interval till execution of the next slot.
|
||||||
intervalMs = this->pst.getIntervalToPreviousSlotMs();
|
intervalMs = this->pollingSeqTable.getIntervalToPreviousSlotMs();
|
||||||
interval = pdMS_TO_TICKS(intervalMs);
|
interval = pdMS_TO_TICKS(intervalMs);
|
||||||
|
|
||||||
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
|
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
|
||||||
@ -132,8 +101,8 @@ void FixedTimeslotTask::taskFunctionality() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::handleMissedDeadline() {
|
void FixedTimeslotTask::handleMissedDeadline() {
|
||||||
if (deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "FreeRTOSTaskIF.h"
|
#include "FreeRTOSTaskIF.h"
|
||||||
#include "fsfw/tasks/FixedSlotSequence.h"
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
#include "fsfw/tasks/FixedTimeslotTaskIF.h"
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
#include "fsfw/tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase, public FreeRTOSTaskIF {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Keep in mind that you need to call before vTaskStartScheduler()!
|
* Keep in mind that you need to call before vTaskStartScheduler()!
|
||||||
@ -23,7 +23,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
|
|||||||
* @return Pointer to the newly created task.
|
* @return Pointer to the newly created task.
|
||||||
*/
|
*/
|
||||||
FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack,
|
FixedTimeslotTask(TaskName name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod overallPeriod, void (*setDeadlineMissedFunc)());
|
TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The destructor of the class.
|
* @brief The destructor of the class.
|
||||||
@ -32,26 +32,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
|
|||||||
* initialization for the PST and the device handlers. This is done by
|
* initialization for the PST and the device handlers. This is done by
|
||||||
* calling the PST's destructor.
|
* calling the PST's destructor.
|
||||||
*/
|
*/
|
||||||
virtual ~FixedTimeslotTask(void);
|
~FixedTimeslotTask() override;
|
||||||
|
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask() override;
|
||||||
/**
|
|
||||||
* This static function can be used as #deadlineMissedFunc.
|
|
||||||
* It counts missedDeadlines and prints the number of missed deadlines
|
|
||||||
* every 10th time.
|
|
||||||
*/
|
|
||||||
static void missedDeadlineCounter();
|
|
||||||
/**
|
|
||||||
* A helper variable to count missed deadlines.
|
|
||||||
*/
|
|
||||||
static uint32_t deadlineMissedCount;
|
|
||||||
|
|
||||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
|
||||||
int8_t executionStep) override;
|
|
||||||
|
|
||||||
uint32_t getPeriodMs() const override;
|
|
||||||
|
|
||||||
ReturnValue_t checkSequence() const override;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
@ -61,17 +44,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
|
|||||||
bool started;
|
bool started;
|
||||||
TaskHandle_t handle;
|
TaskHandle_t handle;
|
||||||
|
|
||||||
FixedSlotSequence pst;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a function pointer that is executed when
|
|
||||||
* a deadline was missed.
|
|
||||||
* @details
|
|
||||||
* Another function may be announced to determine the actions to perform
|
|
||||||
* when a deadline was missed. Currently, only one function for missing
|
|
||||||
* any deadline is allowed. If not used, it shall be declared NULL.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void);
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point for a new task.
|
* @brief This is the entry point for a new task.
|
||||||
* @details
|
* @details
|
||||||
@ -88,7 +60,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
|
|||||||
* It links the functionalities provided by FixedSlotSequence with the
|
* It links the functionalities provided by FixedSlotSequence with the
|
||||||
* OS's System Calls to keep the timing of the periods.
|
* OS's System Calls to keep the timing of the periods.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
[[noreturn]] void taskFunctionality();
|
||||||
|
|
||||||
void handleMissedDeadline();
|
void handleMissedDeadline();
|
||||||
};
|
};
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
class FreeRTOSTaskIF {
|
class FreeRTOSTaskIF {
|
||||||
public:
|
public:
|
||||||
virtual ~FreeRTOSTaskIF() {}
|
virtual ~FreeRTOSTaskIF() = default;
|
||||||
virtual TaskHandle_t getTaskHandle() = 0;
|
virtual TaskHandle_t getTaskHandle() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) {
|
static bool checkMissedDeadline(const TickType_t xLastWakeTime, const TickType_t interval) {
|
||||||
/* Check whether deadline was missed while also taking overflows
|
/* Check whether deadline was missed while also taking overflows
|
||||||
* into account. Drawing this on paper with a timeline helps to understand
|
* into account. Drawing this on paper with a timeline helps to understand
|
||||||
* it. */
|
* it. */
|
||||||
|
@ -5,27 +5,28 @@
|
|||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod setPeriod, TaskDeadlineMissedFunction deadlineMissedFunc)
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(deadlineMissedFunc) {
|
: PeriodicTaskBase(setPeriod, dlmFunc_), started(false), handle(nullptr) {
|
||||||
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
|
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
|
||||||
BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
|
BaseType_t status = xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
|
||||||
if (status != pdPASS) {
|
if (status != pdPASS) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
|
sif::debug << "PeriodicTask::PeriodicTask Insufficient heap memory remaining. Status: "
|
||||||
"Status: "
|
|
||||||
<< status << std::endl;
|
<< status << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printDebug("PeriodicTask::PeriodicTask: Insufficient heap memory remaining. Status: %d\n",
|
||||||
|
status);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask(void) {
|
|
||||||
// Do not delete objects, we were responsible for ptrs only.
|
// Do not delete objects, we were responsible for ptrs only.
|
||||||
}
|
PeriodicTask::~PeriodicTask() = default;
|
||||||
|
|
||||||
void PeriodicTask::taskEntryPoint(void* argument) {
|
void PeriodicTask::taskEntryPoint(void* argument) {
|
||||||
// The argument is re-interpreted as PeriodicTask. The Task object is
|
// The argument is re-interpreted as PeriodicTask. The Task object is
|
||||||
// global, so it is found from any place.
|
// global, so it is found from any place.
|
||||||
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
||||||
/* Task should not start until explicitly requested,
|
/* Task should not start until explicitly requested,
|
||||||
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
|
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
|
||||||
* is running but not if the scheduler is not running.
|
* is running but not if the scheduler is not running.
|
||||||
@ -36,7 +37,7 @@ void PeriodicTask::taskEntryPoint(void* argument) {
|
|||||||
* can continue */
|
* can continue */
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
vTaskSuspend(NULL);
|
vTaskSuspend(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
@ -62,13 +63,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskFunctionality() {
|
[[noreturn]] void PeriodicTask::taskFunctionality() {
|
||||||
TickType_t xLastWakeTime;
|
TickType_t xLastWakeTime;
|
||||||
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
|
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
|
||||||
|
|
||||||
for (auto const& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The xLastWakeTime variable needs to be initialized with the current tick
|
/* The xLastWakeTime variable needs to be initialized with the current tick
|
||||||
count. Note that this is the only time the variable is written to
|
count. Note that this is the only time the variable is written to
|
||||||
@ -77,8 +76,8 @@ void PeriodicTask::taskFunctionality() {
|
|||||||
xLastWakeTime = xTaskGetTickCount();
|
xLastWakeTime = xTaskGetTickCount();
|
||||||
/* Enter the loop that defines the task behavior. */
|
/* Enter the loop that defines the task behavior. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (auto const& object : objectList) {
|
for (auto const& objectPair : objectList) {
|
||||||
object->performOperation();
|
objectPair.first->performOperation(objectPair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
|
#if (tskKERNEL_VERSION_MAJOR == 10 && tskKERNEL_VERSION_MINOR >= 4) || tskKERNEL_VERSION_MAJOR > 10
|
||||||
@ -95,32 +94,10 @@ void PeriodicTask::taskFunctionality() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
|
||||||
"it implement ExecutableObjectIF"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
objectList.push_back(object);
|
|
||||||
object->setTaskIF(this);
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; }
|
|
||||||
|
|
||||||
TaskHandle_t PeriodicTask::getTaskHandle() { return handle; }
|
TaskHandle_t PeriodicTask::getTaskHandle() { return handle; }
|
||||||
|
|
||||||
void PeriodicTask::handleMissedDeadline() {
|
void PeriodicTask::handleMissedDeadline() {
|
||||||
if (deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "FreeRTOSTaskIF.h"
|
#include "FreeRTOSTaskIF.h"
|
||||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
#include "fsfw/tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
@ -17,7 +17,7 @@ class ExecutableObjectIF;
|
|||||||
* periodic activities of multiple objects.
|
* periodic activities of multiple objects.
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
class PeriodicTask : public PeriodicTaskBase, public FreeRTOSTaskIF {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Keep in Mind that you need to call before this vTaskStartScheduler()!
|
* Keep in Mind that you need to call before this vTaskStartScheduler()!
|
||||||
@ -43,7 +43,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
|||||||
* @brief Currently, the executed object's lifetime is not coupled with
|
* @brief Currently, the executed object's lifetime is not coupled with
|
||||||
* the task object's lifetime, so the destructor is empty.
|
* the task object's lifetime, so the destructor is empty.
|
||||||
*/
|
*/
|
||||||
virtual ~PeriodicTask(void);
|
~PeriodicTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -53,27 +53,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
|||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask() override;
|
ReturnValue_t startTask() 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(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;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
@ -83,28 +62,6 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
|||||||
bool started;
|
bool started;
|
||||||
TaskHandle_t handle;
|
TaskHandle_t handle;
|
||||||
|
|
||||||
//! Typedef for the List of objects.
|
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList;
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
/**
|
|
||||||
* @brief The period of the task.
|
|
||||||
* @details
|
|
||||||
* The period determines the frequency of the task's execution.
|
|
||||||
* It is expressed in clock ticks.
|
|
||||||
*/
|
|
||||||
TaskPeriod period;
|
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details
|
|
||||||
* This pointer stores the function that is executed if the task's deadline
|
|
||||||
* is missed so each may react individually on a timing failure.
|
|
||||||
* The pointer may be NULL, then nothing happens on missing the deadline.
|
|
||||||
* The deadline is equal to the next execution of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void);
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the function executed in the new task's context.
|
* @brief This is the function executed in the new task's context.
|
||||||
* @details
|
* @details
|
||||||
@ -125,7 +82,7 @@ class PeriodicTask : public PeriodicTaskIF, public FreeRTOSTaskIF {
|
|||||||
* the next period.
|
* the next period.
|
||||||
* On missing the deadline, the deadlineMissedFunction is executed.
|
* On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
[[noreturn]] void taskFunctionality();
|
||||||
|
|
||||||
void handleMissedDeadline();
|
void handleMissedDeadline();
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
Clock.cpp
|
${LIB_FSFW_NAME}
|
||||||
|
PRIVATE Clock.cpp
|
||||||
FixedTimeslotTask.cpp
|
FixedTimeslotTask.cpp
|
||||||
MessageQueue.cpp
|
MessageQueue.cpp
|
||||||
Mutex.cpp
|
Mutex.cpp
|
||||||
@ -9,19 +10,14 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
|||||||
QueueMapManager.cpp
|
QueueMapManager.cpp
|
||||||
SemaphoreFactory.cpp
|
SemaphoreFactory.cpp
|
||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
taskHelpers.cpp
|
taskHelpers.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
)
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE rt)
|
||||||
rt
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
@ -3,9 +3,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexFactory.h"
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
#include "fsfw/osal/host/FixedTimeslotTask.h"
|
|
||||||
#include "fsfw/osal/host/Mutex.h"
|
#include "fsfw/osal/host/Mutex.h"
|
||||||
#include "fsfw/osal/host/taskHelpers.h"
|
#include "fsfw/osal/host/taskHelpers.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
@ -22,12 +20,8 @@
|
|||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
||||||
TaskStackSize setStack, TaskPeriod setPeriod,
|
TaskStackSize setStack, TaskPeriod setPeriod,
|
||||||
void (*setDeadlineMissedFunc)())
|
TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false),
|
: FixedTimeslotTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
|
||||||
pollingSeqTable(setPeriod * 1000),
|
|
||||||
taskName(name),
|
|
||||||
period(setPeriod),
|
|
||||||
deadlineMissedFunc(setDeadlineMissedFunc) {
|
|
||||||
// It is propably possible to set task priorities by using the native
|
// It is propably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
|
||||||
@ -39,7 +33,7 @@ FixedTimeslotTask::FixedTimeslotTask(const char* name, TaskPriority setPriority,
|
|||||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask(void) {
|
FixedTimeslotTask::~FixedTimeslotTask() {
|
||||||
// Do not delete objects, we were responsible for ptrs only.
|
// Do not delete objects, we were responsible for ptrs only.
|
||||||
terminateThread = true;
|
terminateThread = true;
|
||||||
if (mainThread.joinable()) {
|
if (mainThread.joinable()) {
|
||||||
@ -48,7 +42,7 @@ FixedTimeslotTask::~FixedTimeslotTask(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
void FixedTimeslotTask::taskEntryPoint(void* argument) {
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
// we have to suspend/block here until the task is started.
|
// we have to suspend/block here until the task is started.
|
||||||
@ -81,7 +75,9 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
void FixedTimeslotTask::taskFunctionality() {
|
||||||
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||||
|
// Ignore returnvalue for now
|
||||||
|
static_cast<void>(result);
|
||||||
|
|
||||||
// A local iterator for the Polling Sequence Table is created to
|
// A local iterator for the Polling Sequence Table is created to
|
||||||
// find the start time for the first entry.
|
// find the start time for the first entry.
|
||||||
@ -106,37 +102,15 @@ void FixedTimeslotTask::taskFunctionality() {
|
|||||||
// we need to wait before executing the current slot
|
// we need to wait before executing the current slot
|
||||||
// this gives us the time to wait:
|
// this gives us the time to wait:
|
||||||
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
|
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
|
||||||
delayForInterval(¤tStartTime, interval);
|
if (not delayForInterval(¤tStartTime, interval)) {
|
||||||
// TODO deadline missed check
|
if (dlmFunc != nullptr) {
|
||||||
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF* executableObject =
|
|
||||||
ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (executableObject != nullptr) {
|
|
||||||
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << "0x" << componentId
|
|
||||||
<< "not found, "
|
|
||||||
"not adding it to PST.."
|
|
||||||
<< std::dec << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("Component 0x%08x not found, not adding it to PST..\n",
|
|
||||||
static_cast<unsigned int>(componentId));
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pollingSeqTable.checkSequence(); }
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return period * 1000; }
|
|
||||||
|
|
||||||
bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
bool FixedTimeslotTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
||||||
bool shouldDelay = false;
|
bool shouldDelay = false;
|
||||||
// Get current wakeup time
|
// Get current wakeup time
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "../../tasks/FixedSlotSequence.h"
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
#include "../../tasks/FixedTimeslotTaskIF.h"
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
#include "../../tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class ExecutableObjectIF;
|
|||||||
* @details
|
* @details
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Standard constructor of the class.
|
* @brief Standard constructor of the class.
|
||||||
@ -39,7 +39,7 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* @brief Currently, the executed object's lifetime is not coupled with
|
* @brief Currently, the executed object's lifetime is not coupled with
|
||||||
* the task object's lifetime, so the destructor is empty.
|
* the task object's lifetime, so the destructor is empty.
|
||||||
*/
|
*/
|
||||||
virtual ~FixedTimeslotTask(void);
|
~FixedTimeslotTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -48,56 +48,22 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* The address of the task object is passed as an argument
|
* The address of the task object is passed as an argument
|
||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask() override;
|
||||||
|
|
||||||
/**
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
* Add timeslot to the polling sequence table.
|
|
||||||
* @param componentId
|
|
||||||
* @param slotTimeMs
|
|
||||||
* @param executionStep
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
|
||||||
|
|
||||||
ReturnValue_t checkSequence() const override;
|
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using chron_ms = std::chrono::milliseconds;
|
using chron_ms = std::chrono::milliseconds;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
//!< Typedef for the List of objects.
|
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList;
|
|
||||||
std::thread mainThread;
|
std::thread mainThread;
|
||||||
std::atomic<bool> terminateThread{false};
|
std::atomic<bool> terminateThread{false};
|
||||||
|
|
||||||
//! Polling sequence table which contains the object to execute
|
|
||||||
//! and information like the timeslots and the passed execution step.
|
|
||||||
FixedSlotSequence pollingSeqTable;
|
|
||||||
|
|
||||||
std::condition_variable initCondition;
|
std::condition_variable initCondition;
|
||||||
std::mutex initMutex;
|
std::mutex initMutex;
|
||||||
std::string taskName;
|
std::string taskName;
|
||||||
/**
|
|
||||||
* @brief The period of the task.
|
|
||||||
* @details
|
|
||||||
* The period determines the frequency of the task's execution.
|
|
||||||
* It is expressed in clock ticks.
|
|
||||||
*/
|
|
||||||
TaskPeriod period;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details
|
|
||||||
* This pointer stores the function that is executed if the task's deadline
|
|
||||||
* is missed. So, each may react individually on a timing failure.
|
|
||||||
* The pointer may be NULL, then nothing happens on missing the deadline.
|
|
||||||
* The deadline is equal to the next execution of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void);
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the function executed in the new task's context.
|
* @brief This is the function executed in the new task's context.
|
||||||
* @details
|
* @details
|
||||||
@ -117,9 +83,9 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF {
|
|||||||
* the checkAndRestartPeriod system call blocks the task until the next
|
* the checkAndRestartPeriod system call blocks the task until the next
|
||||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
void taskFunctionality();
|
||||||
|
|
||||||
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
|
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */
|
||||||
|
@ -3,13 +3,10 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "fsfw/ipc/MutexFactory.h"
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/osal/host/Mutex.h"
|
#include "fsfw/osal/host/Mutex.h"
|
||||||
#include "fsfw/osal/host/taskHelpers.h"
|
#include "fsfw/osal/host/taskHelpers.h"
|
||||||
#include "fsfw/platform.h"
|
#include "fsfw/platform.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WIN)
|
#if defined(PLATFORM_WIN)
|
||||||
#include <processthreadsapi.h>
|
#include <processthreadsapi.h>
|
||||||
@ -20,8 +17,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)())
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: started(false), taskName(name), period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
|
: PeriodicTaskBase(setPeriod, dlmFunc_), started(false), taskName(name) {
|
||||||
// It is probably possible to set task priorities by using the native
|
// It is probably possible to set task priorities by using the native
|
||||||
// task handles for Windows / Linux
|
// task handles for Windows / Linux
|
||||||
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
|
||||||
@ -33,7 +30,7 @@ PeriodicTask::PeriodicTask(const char* name, TaskPriority setPriority, TaskStack
|
|||||||
tasks::insertTaskName(mainThread.get_id(), taskName);
|
tasks::insertTaskName(mainThread.get_id(), taskName);
|
||||||
}
|
}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask(void) {
|
PeriodicTask::~PeriodicTask() {
|
||||||
// Do not delete objects, we were responsible for ptrs only.
|
// Do not delete objects, we were responsible for ptrs only.
|
||||||
terminateThread = true;
|
terminateThread = true;
|
||||||
if (mainThread.joinable()) {
|
if (mainThread.joinable()) {
|
||||||
@ -42,7 +39,7 @@ PeriodicTask::~PeriodicTask(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskEntryPoint(void* argument) {
|
void PeriodicTask::taskEntryPoint(void* argument) {
|
||||||
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
||||||
|
|
||||||
if (not originalTask->started) {
|
if (not originalTask->started) {
|
||||||
// we have to suspend/block here until the task is started.
|
// we have to suspend/block here until the task is started.
|
||||||
@ -75,47 +72,27 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicTask::taskFunctionality() {
|
void PeriodicTask::taskFunctionality() {
|
||||||
for (const auto& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
|
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period * 1000));
|
||||||
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
|
auto currentStartTime{std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::system_clock::now().time_since_epoch())};
|
std::chrono::system_clock::now().time_since_epoch())};
|
||||||
auto nextStartTime{currentStartTime};
|
|
||||||
|
|
||||||
/* Enter the loop that defines the task behavior. */
|
/* Enter the loop that defines the task behavior. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (terminateThread.load()) {
|
if (terminateThread.load()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (const auto& object : objectList) {
|
for (const auto& objectPair : objectList) {
|
||||||
object->performOperation();
|
objectPair.first->performOperation(objectPair.second);
|
||||||
}
|
}
|
||||||
if (not delayForInterval(¤tStartTime, periodChrono)) {
|
if (not delayForInterval(¤tStartTime, periodChrono)) {
|
||||||
if (deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
this->dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
object->setTaskIF(this);
|
|
||||||
objectList.push_back(object);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PeriodicTask::getPeriodMs() const { return period * 1000; }
|
|
||||||
|
|
||||||
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval) {
|
||||||
bool shouldDelay = false;
|
bool shouldDelay = false;
|
||||||
// Get current wakeup time
|
// Get current wakeup time
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
#include "../../tasks/Typedef.h"
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ class ExecutableObjectIF;
|
|||||||
*
|
*
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class PeriodicTask : public PeriodicTaskIF {
|
class PeriodicTask : public PeriodicTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Standard constructor of the class.
|
* @brief Standard constructor of the class.
|
||||||
@ -34,12 +34,12 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
* assigned.
|
* assigned.
|
||||||
*/
|
*/
|
||||||
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
PeriodicTask(const char* name, TaskPriority setPriority, TaskStackSize setStack,
|
||||||
TaskPeriod setPeriod, void (*setDeadlineMissedFunc)());
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
|
||||||
/**
|
/**
|
||||||
* @brief Currently, the executed object's lifetime is not coupled with
|
* @brief Currently, the executed object's lifetime is not coupled with
|
||||||
* the task object's lifetime, so the destructor is empty.
|
* the task object's lifetime, so the destructor is empty.
|
||||||
*/
|
*/
|
||||||
virtual ~PeriodicTask(void);
|
~PeriodicTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -48,63 +48,20 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
* The address of the task object is passed as an argument
|
* The address of the task object is passed as an argument
|
||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask() 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(object_id_t object);
|
|
||||||
|
|
||||||
/**
|
ReturnValue_t sleepFor(uint32_t ms) 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
|
|
||||||
* -@c RETURN_OK on success
|
|
||||||
* -@c RETURN_FAILED if the object could not be added.
|
|
||||||
*/
|
|
||||||
ReturnValue_t addComponent(ExecutableObjectIF* object);
|
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using chron_ms = std::chrono::milliseconds;
|
using chron_ms = std::chrono::milliseconds;
|
||||||
bool started;
|
bool started;
|
||||||
//!< Typedef for the List of objects.
|
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList;
|
|
||||||
std::thread mainThread;
|
std::thread mainThread;
|
||||||
std::atomic<bool> terminateThread{false};
|
std::atomic<bool> terminateThread{false};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
|
|
||||||
std::condition_variable initCondition;
|
std::condition_variable initCondition;
|
||||||
std::mutex initMutex;
|
std::mutex initMutex;
|
||||||
std::string taskName;
|
std::string taskName;
|
||||||
/**
|
|
||||||
* @brief The period of the task.
|
|
||||||
* @details
|
|
||||||
* The period determines the frequency of the task's execution.
|
|
||||||
* It is expressed in clock ticks.
|
|
||||||
*/
|
|
||||||
TaskPeriod period;
|
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details
|
|
||||||
* This pointer stores the function that is executed if the task's deadline
|
|
||||||
* is missed. So, each may react individually on a timing failure.
|
|
||||||
* The pointer may be NULL, then nothing happens on missing the deadline.
|
|
||||||
* The deadline is equal to the next execution of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void);
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the function executed in the new task's context.
|
* @brief This is the function executed in the new task's context.
|
||||||
* @details
|
* @details
|
||||||
@ -124,9 +81,9 @@ class PeriodicTask : public PeriodicTaskIF {
|
|||||||
* the checkAndRestartPeriod system call blocks the task until the next
|
* the checkAndRestartPeriod system call blocks the task until the next
|
||||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
void taskFunctionality();
|
||||||
|
|
||||||
bool delayForInterval(chron_ms* previousWakeTimeMs, const chron_ms interval);
|
static bool delayForInterval(chron_ms* previousWakeTimeMs, chron_ms interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PERIODICTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ */
|
||||||
|
@ -14,9 +14,9 @@ TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
|||||||
// Not used for the host implementation for now because C++ thread abstraction is used
|
// Not used for the host implementation for now because C++ thread abstraction is used
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
|
||||||
|
|
||||||
TaskFactory::TaskFactory() {}
|
TaskFactory::TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory::~TaskFactory() {}
|
TaskFactory::~TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
std::mutex nameMapLock;
|
std::mutex nameMapLock;
|
||||||
std::map<std::thread::id, std::string> taskNameMap;
|
std::map<std::thread::id, std::string> taskNameMap;
|
||||||
|
|
||||||
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, std::string taskName) {
|
ReturnValue_t tasks::insertTaskName(std::thread::id threadId, const std::string& taskName) {
|
||||||
std::lock_guard<std::mutex> lg(nameMapLock);
|
std::lock_guard<std::mutex> lg(nameMapLock);
|
||||||
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
auto returnPair = taskNameMap.emplace(threadId, taskName);
|
||||||
if (not returnPair.second) {
|
if (not returnPair.second) {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace tasks {
|
namespace tasks {
|
||||||
|
|
||||||
ReturnValue_t insertTaskName(std::thread::id threadId, std::string taskName);
|
ReturnValue_t insertTaskName(std::thread::id threadId, const std::string& taskName);
|
||||||
std::string getTaskName(std::thread::id threadId);
|
std::string getTaskName(std::thread::id threadId);
|
||||||
|
|
||||||
} // namespace tasks
|
} // namespace tasks
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(
|
||||||
Clock.cpp
|
${LIB_FSFW_NAME}
|
||||||
|
PRIVATE Clock.cpp
|
||||||
BinarySemaphore.cpp
|
BinarySemaphore.cpp
|
||||||
CountingSemaphore.cpp
|
CountingSemaphore.cpp
|
||||||
FixedTimeslotTask.cpp
|
FixedTimeslotTask.cpp
|
||||||
@ -13,17 +14,12 @@ target_sources(${LIB_FSFW_NAME} PRIVATE
|
|||||||
SemaphoreFactory.cpp
|
SemaphoreFactory.cpp
|
||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
tcpipHelpers.cpp
|
tcpipHelpers.cpp
|
||||||
unixUtility.cpp
|
unixUtility.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PUBLIC
|
target_link_libraries(${LIB_FSFW_NAME} PUBLIC rt)
|
||||||
rt
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
#include "fsfw/osal/linux/FixedTimeslotTask.h"
|
#include "fsfw/osal/linux/FixedTimeslotTask.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <climits>
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
|
||||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_,
|
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
uint32_t periodMs_)
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: PosixThread(name_, priority_, stackSize_), pst(periodMs_), started(false) {}
|
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
|
||||||
|
posixThread(name_, priority_, stackSize_),
|
||||||
FixedTimeslotTask::~FixedTimeslotTask() {}
|
started(false) {}
|
||||||
|
|
||||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
FixedTimeslotTask* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
auto* originalTask(reinterpret_cast<FixedTimeslotTask*>(arg));
|
||||||
// The task's functionality is called.
|
// The task's functionality is called.
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -24,7 +22,7 @@ void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
|||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||||
started = true;
|
started = true;
|
||||||
createTask(&taskEntryPoint, this);
|
posixThread.createTask(&taskEntryPoint, this);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,63 +30,36 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
|
|||||||
return PosixThread::sleep((uint64_t)ms * 1000000);
|
return PosixThread::sleep((uint64_t)ms * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); }
|
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF* executableObject =
|
|
||||||
ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (executableObject != nullptr) {
|
|
||||||
pst.addSlot(componentId, slotTimeMs, executionStep, executableObject, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst"
|
|
||||||
<< std::dec << std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); }
|
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
|
||||||
// Like FreeRTOS pthreads are running as soon as they are created
|
// Like FreeRTOS pthreads are running as soon as they are created
|
||||||
if (!started) {
|
if (!started) {
|
||||||
suspend();
|
posixThread.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
pst.intializeSequenceAfterTaskCreation();
|
// Returnvalue ignored for now
|
||||||
|
static_cast<void>(pollingSeqTable.intializeSequenceAfterTaskCreation());
|
||||||
|
|
||||||
// The start time for the first entry is read.
|
// The start time for the first entry is read.
|
||||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
|
||||||
uint64_t interval = pst.getIntervalToNextSlotMs();
|
uint32_t interval = 0;
|
||||||
|
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (true) {
|
||||||
if (pst.slotFollowsImmediately()) {
|
if (pollingSeqTable.slotFollowsImmediately()) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
// The interval for the next polling slot is selected.
|
// The interval for the next polling slot is selected.
|
||||||
interval = this->pst.getIntervalToPreviousSlotMs();
|
interval = pollingSeqTable.getIntervalToPreviousSlotMs();
|
||||||
// The period is checked and restarted with the new interval.
|
// The period is checked and restarted with the new interval.
|
||||||
// If the deadline was missed, the deadlineMissedFunc is called.
|
// If the deadline was missed, the deadlineMissedFunc is called.
|
||||||
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
|
if (!PosixThread::delayUntil(&lastWakeTime, interval)) {
|
||||||
// No time left on timer -> we missed the deadline
|
// No time left on timer -> we missed the deadline
|
||||||
missedDeadlineCounter();
|
if(dlmFunc != nullptr){
|
||||||
|
dlmFunc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The device handler for this slot is executed and the next one is chosen.
|
// The device handler for this slot is executed and the next one is chosen.
|
||||||
this->pst.executeAndAdvance();
|
pollingSeqTable.executeAndAdvance();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
|
||||||
FixedTimeslotTask::deadlineMissedCount++;
|
|
||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "../../tasks/FixedSlotSequence.h"
|
|
||||||
#include "../../tasks/FixedTimeslotTaskIF.h"
|
|
||||||
#include "PosixThread.h"
|
#include "PosixThread.h"
|
||||||
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
|
#include "fsfw/tasks/definitions.h"
|
||||||
|
|
||||||
class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a generic periodic task.
|
* Create a generic periodic task.
|
||||||
@ -21,29 +22,13 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* @param period_
|
* @param period_
|
||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_);
|
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||||
virtual ~FixedTimeslotTask();
|
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
|
||||||
|
~FixedTimeslotTask() override = default;
|
||||||
|
|
||||||
virtual ReturnValue_t startTask();
|
ReturnValue_t startTask() override;
|
||||||
|
|
||||||
virtual ReturnValue_t sleepFor(uint32_t ms);
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
virtual uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
|
||||||
|
|
||||||
virtual ReturnValue_t checkSequence() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This static function can be used as #deadlineMissedFunc.
|
|
||||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
|
||||||
*/
|
|
||||||
static void missedDeadlineCounter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper variable to count missed deadlines.
|
|
||||||
*/
|
|
||||||
static uint32_t deadlineMissedCount;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -53,9 +38,12 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* It links the functionalities provided by FixedSlotSequence with the
|
* It links the functionalities provided by FixedSlotSequence with the
|
||||||
* OS's System Calls to keep the timing of the periods.
|
* OS's System Calls to keep the timing of the periods.
|
||||||
*/
|
*/
|
||||||
virtual void taskFunctionality();
|
[[noreturn]] virtual void taskFunctionality();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
PosixThread posixThread;
|
||||||
|
bool started;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point in a new thread.
|
* @brief This is the entry point in a new thread.
|
||||||
*
|
*
|
||||||
@ -68,9 +56,6 @@ class FixedTimeslotTask : public FixedTimeslotTaskIF, public PosixThread {
|
|||||||
* arbitrary data.
|
* arbitrary data.
|
||||||
*/
|
*/
|
||||||
static void* taskEntryPoint(void* arg);
|
static void* taskEntryPoint(void* arg);
|
||||||
FixedSlotSequence pst;
|
|
||||||
|
|
||||||
bool started;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
|
#endif /* FSFW_OSAL_LINUX_FIXEDTIMESLOTTASK_H_ */
|
||||||
|
@ -1,86 +1,54 @@
|
|||||||
#include "fsfw/osal/linux/PeriodicPosixTask.h"
|
#include "PeriodicPosixTask.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
||||||
uint32_t period_, void(deadlineMissedFunc_)())
|
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: PosixThread(name_, priority_, stackSize_),
|
: PeriodicTaskBase(period_, dlmFunc_),
|
||||||
objectList(),
|
posixThread(name_, priority_, stackSize_),
|
||||||
started(false),
|
started(false) {}
|
||||||
periodMs(period_),
|
|
||||||
deadlineMissedFunc(deadlineMissedFunc_) {}
|
|
||||||
|
|
||||||
PeriodicPosixTask::~PeriodicPosixTask() {
|
|
||||||
// Not Implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||||
// The argument is re-interpreted as PollingTask.
|
// The argument is re-interpreted as PollingTask.
|
||||||
PeriodicPosixTask* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
|
auto* originalTask(reinterpret_cast<PeriodicPosixTask*>(arg));
|
||||||
// The task's functionality is called.
|
// The task's functionality is called.
|
||||||
originalTask->taskFunctionality();
|
originalTask->taskFunctionality();
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
|
|
||||||
<< " it implements ExecutableObjectIF!" << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError(
|
|
||||||
"PeriodicTask::addComponent: Invalid object. Make sure it "
|
|
||||||
"implements ExecutableObjectIF!\n");
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
objectList.push_back(object);
|
|
||||||
object->setTaskIF(this);
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
|
||||||
return PosixThread::sleep((uint64_t)ms * 1000000);
|
return PosixThread::sleep(static_cast<uint64_t>(ms) * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicPosixTask::startTask(void) {
|
ReturnValue_t PeriodicPosixTask::startTask() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
started = true;
|
started = true;
|
||||||
PosixThread::createTask(&taskEntryPoint, this);
|
posixThread.createTask(&taskEntryPoint, this);
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicPosixTask::taskFunctionality(void) {
|
[[noreturn]] void PeriodicPosixTask::taskFunctionality() {
|
||||||
if (not started) {
|
if (not started) {
|
||||||
suspend();
|
posixThread.suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
|
uint64_t lastWakeTime = PosixThread::getCurrentMonotonicTimeMs();
|
||||||
|
uint64_t periodMs = getPeriodMs();
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (true) {
|
||||||
for (auto const& object : objectList) {
|
for (auto const& objOpCodePair : objectList) {
|
||||||
object->performOperation();
|
objOpCodePair.first->performOperation(objOpCodePair.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
if (not PosixThread::delayUntil(&lastWakeTime, periodMs)) {
|
||||||
if (this->deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PeriodicPosixTask::getPeriodMs() const { return periodMs; }
|
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../../tasks/ExecutableObjectIF.h"
|
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
|
||||||
#include "PosixThread.h"
|
#include "PosixThread.h"
|
||||||
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
|
||||||
class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
class PeriodicPosixTask : public PeriodicTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a generic periodic task.
|
* Create a generic periodic task.
|
||||||
@ -22,9 +23,9 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* @param period_
|
* @param period_
|
||||||
* @param deadlineMissedFunc_
|
* @param deadlineMissedFunc_
|
||||||
*/
|
*/
|
||||||
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_,
|
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
|
||||||
void (*deadlineMissedFunc_)());
|
TaskDeadlineMissedFunction dlmFunc_);
|
||||||
virtual ~PeriodicPosixTask();
|
~PeriodicPosixTask() override = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -34,42 +35,17 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask() override;
|
ReturnValue_t startTask() 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 RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::vector<ExecutableObjectIF*> ObjectList; //!< Typedef for the List of objects.
|
PosixThread posixThread;
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Flag to indicate that the task was started and is allowed to run
|
* @brief Flag to indicate that the task was started and is allowed to run
|
||||||
*/
|
*/
|
||||||
bool started;
|
bool started;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Period of the task in milliseconds
|
|
||||||
*/
|
|
||||||
uint32_t periodMs;
|
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
@ -78,7 +54,7 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
|
* will be blocked until the next period. On missing the deadline, the deadlineMissedFunction is
|
||||||
* executed.
|
* executed.
|
||||||
*/
|
*/
|
||||||
virtual void taskFunctionality(void);
|
[[noreturn]] virtual void taskFunctionality();
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point in a new thread.
|
* @brief This is the entry point in a new thread.
|
||||||
*
|
*
|
||||||
@ -86,14 +62,6 @@ class PeriodicPosixTask : public PosixThread, public PeriodicTaskIF {
|
|||||||
* of the child class. Needs a valid pointer to the derived class.
|
* of the child class. Needs a valid pointer to the derived class.
|
||||||
*/
|
*/
|
||||||
static void* taskEntryPoint(void* arg);
|
static void* taskEntryPoint(void* arg);
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details This pointer stores the function that is executed if the task's deadline is missed.
|
|
||||||
* So, each may react individually on a timing failure. The pointer may be
|
|
||||||
* NULL, then nothing happens on missing the deadline. The deadline is equal to the next execution
|
|
||||||
* of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_PERIODICPOSIXTASK_H_ */
|
||||||
|
@ -35,6 +35,21 @@ class PosixThread {
|
|||||||
*/
|
*/
|
||||||
void resume();
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function that has to be called by derived class because the
|
||||||
|
* derived class pointer has to be valid as argument.
|
||||||
|
* @details
|
||||||
|
* This function creates a pthread with the given parameters. As the
|
||||||
|
* function requires a pointer to the derived object it has to be called
|
||||||
|
* after the this pointer of the derived object is valid.
|
||||||
|
* Sets the taskEntryPoint as function to be called by new a thread.
|
||||||
|
* @param fnc_ Function which will be executed by the thread.
|
||||||
|
* @param arg_
|
||||||
|
* argument of the taskEntryPoint function, needs to be this pointer
|
||||||
|
* of derived class
|
||||||
|
*/
|
||||||
|
void createTask(void* (*fnc_)(void*), void* arg_);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay function similar to FreeRtos delayUntil function
|
* Delay function similar to FreeRtos delayUntil function
|
||||||
*
|
*
|
||||||
@ -55,21 +70,6 @@ class PosixThread {
|
|||||||
protected:
|
protected:
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function that has to be called by derived class because the
|
|
||||||
* derived class pointer has to be valid as argument.
|
|
||||||
* @details
|
|
||||||
* This function creates a pthread with the given parameters. As the
|
|
||||||
* function requires a pointer to the derived object it has to be called
|
|
||||||
* after the this pointer of the derived object is valid.
|
|
||||||
* Sets the taskEntryPoint as function to be called by new a thread.
|
|
||||||
* @param fnc_ Function which will be executed by the thread.
|
|
||||||
* @param arg_
|
|
||||||
* argument of the taskEntryPoint function, needs to be this pointer
|
|
||||||
* of derived class
|
|
||||||
*/
|
|
||||||
void createTask(void* (*fnc_)(void*), void* arg_);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char name[PTHREAD_MAX_NAMELEN];
|
char name[PTHREAD_MAX_NAMELEN];
|
||||||
int priority;
|
int priority;
|
||||||
|
@ -8,21 +8,22 @@
|
|||||||
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||||
|
|
||||||
TaskFactory::~TaskFactory() {}
|
TaskFactory::~TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||||
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000,
|
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
deadLineMissedFunction_);
|
deadLineMissedFunction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_ * 1000);
|
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||||
|
deadLineMissedFunction_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
target_sources(${LIB_FSFW_NAME}
|
target_sources(
|
||||||
PRIVATE
|
${LIB_FSFW_NAME}
|
||||||
Clock.cpp
|
PRIVATE Clock.cpp
|
||||||
CpuUsage.cpp
|
CpuUsage.cpp
|
||||||
InitTask.cpp
|
InitTask.cpp
|
||||||
InternalErrorCodes.cpp
|
InternalErrorCodes.cpp
|
||||||
@ -14,7 +14,4 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
RTEMSTaskBase.cpp
|
RTEMSTaskBase.cpp
|
||||||
TaskFactory.cpp
|
TaskFactory.cpp
|
||||||
BinarySemaphore.cpp
|
BinarySemaphore.cpp
|
||||||
SemaphoreFactory.cpp
|
SemaphoreFactory.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,42 +1,32 @@
|
|||||||
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
|
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
|
||||||
|
|
||||||
#include <rtems/bspIo.h>
|
|
||||||
#include <rtems/io.h>
|
#include <rtems/io.h>
|
||||||
#include <rtems/rtems/ratemon.h>
|
|
||||||
#include <rtems/rtems/status.h>
|
#include <rtems/rtems/status.h>
|
||||||
#include <rtems/rtems/tasks.h>
|
#include <rtems/rtems/tasks.h>
|
||||||
#include <rtems/rtems/types.h>
|
#include <rtems/rtems/types.h>
|
||||||
#include <sys/_stdint.h>
|
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
|
||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/tasks/FixedSequenceSlot.h"
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <list>
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
|
|
||||||
|
|
||||||
FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority,
|
FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority,
|
||||||
size_t setStack, uint32_t setOverallPeriod,
|
size_t setStack, TaskPeriod setOverallPeriod,
|
||||||
void (*setDeadlineMissedFunc)(void))
|
TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: RTEMSTaskBase(setPriority, setStack, name), periodId(0), pst(setOverallPeriod) {
|
: FixedTimeslotTaskBase(setOverallPeriod, dlmFunc_),
|
||||||
// All additional attributes are applied to the object.
|
RTEMSTaskBase(setPriority, setStack, name),
|
||||||
this->deadlineMissedFunc = setDeadlineMissedFunc;
|
periodId(0) {}
|
||||||
}
|
|
||||||
|
|
||||||
FixedTimeslotTask::~FixedTimeslotTask() {}
|
FixedTimeslotTask::~FixedTimeslotTask() = default;
|
||||||
|
|
||||||
rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
|
rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
|
||||||
/* The argument is re-interpreted as a FixedTimeslotTask */
|
/* The argument is re-interpreted as a FixedTimeslotTask */
|
||||||
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument));
|
auto *originalTask(reinterpret_cast<FixedTimeslotTask *>(argument));
|
||||||
/* The task's functionality is called. */
|
/* The task's functionality is called. */
|
||||||
return originalTask->taskFunctionality();
|
return originalTask->taskFunctionality();
|
||||||
/* Should never be reached */
|
/* Should never be reached */
|
||||||
@ -46,16 +36,6 @@ rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixedTimeslotTask::missedDeadlineCounter() {
|
|
||||||
FixedTimeslotTask::deadlineMissedCount++;
|
|
||||||
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount << " deadlines."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::startTask() {
|
ReturnValue_t FixedTimeslotTask::startTask() {
|
||||||
rtems_status_code status =
|
rtems_status_code status =
|
||||||
rtems_task_start(id, FixedTimeslotTask::taskEntryPoint, rtems_task_argument((void *)this));
|
rtems_task_start(id, FixedTimeslotTask::taskEntryPoint, rtems_task_argument((void *)this));
|
||||||
@ -79,54 +59,35 @@ ReturnValue_t FixedTimeslotTask::startTask() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, uint32_t slotTimeMs,
|
[[noreturn]] void FixedTimeslotTask::taskFunctionality() {
|
||||||
int8_t executionStep) {
|
|
||||||
ExecutableObjectIF *object = ObjectManager::instance()->get<ExecutableObjectIF>(componentId);
|
|
||||||
if (object != nullptr) {
|
|
||||||
pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Component " << std::hex << componentId << " not found, not adding it to pst"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t FixedTimeslotTask::getPeriodMs() const { return pst.getLengthMs(); }
|
|
||||||
|
|
||||||
ReturnValue_t FixedTimeslotTask::checkSequence() const { return pst.checkSequence(); }
|
|
||||||
|
|
||||||
void FixedTimeslotTask::taskFunctionality() {
|
|
||||||
/* A local iterator for the Polling Sequence Table is created to find the start time for
|
/* A local iterator for the Polling Sequence Table is created to find the start time for
|
||||||
the first entry. */
|
the first entry. */
|
||||||
FixedSlotSequence::SlotListIter it = pst.current;
|
auto it = pollingSeqTable.current;
|
||||||
|
|
||||||
/* Initialize the PST with the correct calling task */
|
/* Initialize the PST with the correct calling task */
|
||||||
pst.intializeSequenceAfterTaskCreation();
|
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||||
|
|
||||||
/* The start time for the first entry is read. */
|
/* The start time for the first entry is read. */
|
||||||
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
|
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
|
||||||
RTEMSTaskBase::setAndStartPeriod(interval, &periodId);
|
RTEMSTaskBase::setAndStartPeriod(interval, &periodId);
|
||||||
// The task's "infinite" inner loop is entered.
|
// The task's "infinite" inner loop is entered.
|
||||||
while (1) {
|
while (true) {
|
||||||
if (pst.slotFollowsImmediately()) {
|
if (pollingSeqTable.slotFollowsImmediately()) {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
} else {
|
} else {
|
||||||
/* The interval for the next polling slot is selected. */
|
/* The interval for the next polling slot is selected. */
|
||||||
interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
|
interval = RtemsBasic::convertMsToTicks(pollingSeqTable.getIntervalToNextSlotMs());
|
||||||
/* The period is checked and restarted with the new interval.
|
/* The period is checked and restarted with the new interval.
|
||||||
If the deadline was missed, the deadlineMissedFunc is called. */
|
If the deadline was missed, the deadlineMissedFunc is called. */
|
||||||
rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId);
|
rtems_status_code status = RTEMSTaskBase::restartPeriod(interval, periodId);
|
||||||
if (status == RTEMS_TIMEOUT) {
|
if (status == RTEMS_TIMEOUT) {
|
||||||
if (this->deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* The device handler for this slot is executed and the next one is chosen. */
|
/* The device handler for this slot is executed and the next one is chosen. */
|
||||||
this->pst.executeAndAdvance();
|
this->pollingSeqTable.executeAndAdvance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
|
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
|
||||||
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
|
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
|
||||||
|
|
||||||
#include "../../tasks/FixedSlotSequence.h"
|
|
||||||
#include "../../tasks/FixedTimeslotTaskIF.h"
|
|
||||||
#include "RTEMSTaskBase.h"
|
#include "RTEMSTaskBase.h"
|
||||||
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
|
#include "fsfw/tasks/FixedTimeslotTaskBase.h"
|
||||||
|
|
||||||
class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
|
class FixedTimeslotTask : public FixedTimeslotTaskBase, public RTEMSTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief The standard constructor of the class.
|
* @brief The standard constructor of the class.
|
||||||
@ -17,7 +17,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
|
|||||||
* @param getPst The object id of the completely initialized polling sequence.
|
* @param getPst The object id of the completely initialized polling sequence.
|
||||||
*/
|
*/
|
||||||
FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize,
|
FixedTimeslotTask(const char *name, rtems_task_priority setPriority, size_t setStackSize,
|
||||||
uint32_t overallPeriod, void (*setDeadlineMissedFunc)());
|
TaskPeriod overallPeriod, TaskDeadlineMissedFunction dlmFunc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The destructor of the class.
|
* @brief The destructor of the class.
|
||||||
@ -25,44 +25,17 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
|
|||||||
* The destructor frees all heap memory that was allocated on thread initialization
|
* The destructor frees all heap memory that was allocated on thread initialization
|
||||||
* for the PST andthe device handlers. This is done by calling the PST's destructor.
|
* for the PST andthe device handlers. This is done by calling the PST's destructor.
|
||||||
*/
|
*/
|
||||||
virtual ~FixedTimeslotTask(void);
|
~FixedTimeslotTask() override;
|
||||||
|
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask(void);
|
||||||
/**
|
|
||||||
* This static function can be used as #deadlineMissedFunc.
|
|
||||||
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
|
|
||||||
*/
|
|
||||||
static void missedDeadlineCounter();
|
|
||||||
/**
|
|
||||||
* A helper variable to count missed deadlines.
|
|
||||||
*/
|
|
||||||
static uint32_t deadlineMissedCount;
|
|
||||||
|
|
||||||
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
uint32_t getPeriodMs() const;
|
|
||||||
|
|
||||||
ReturnValue_t checkSequence() const;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief id of the associated OS period
|
* @brief id of the associated OS period
|
||||||
*/
|
*/
|
||||||
rtems_id periodId;
|
rtems_id periodId;
|
||||||
|
|
||||||
FixedSlotSequence pst;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
|
|
||||||
*
|
|
||||||
* @details
|
|
||||||
* Another function may be announced to determine the actions to perform when a deadline
|
|
||||||
* was missed. Currently, only one function for missing any deadline is allowed.
|
|
||||||
* If not used, it shall be declared NULL.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void) = nullptr;
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the entry point in a new polling thread.
|
* @brief This is the entry point in a new polling thread.
|
||||||
* @details This method is the entry point in the new thread
|
* @details This method is the entry point in the new thread
|
||||||
@ -76,7 +49,7 @@ class FixedTimeslotTask : public RTEMSTaskBase, public FixedTimeslotTaskIF {
|
|||||||
* It links the functionalities provided by FixedSlotSequence with the OS's system calls to
|
* It links the functionalities provided by FixedSlotSequence with the OS's system calls to
|
||||||
* keep the timing of the periods.
|
* keep the timing of the periods.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
[[noreturn]] void taskFunctionality();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */
|
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */
|
||||||
|
@ -65,7 +65,7 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueu
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t returnCode = convertReturnCode(result);
|
ReturnValue_t returnCode = convertReturnCode(result);
|
||||||
if (result == MessageQueueIF::EMPTY) {
|
if (returnCode == MessageQueueIF::EMPTY) {
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class MessageQueue : public MessageQueueBase {
|
|||||||
* @param max_message_size With this parameter, the maximum message size can be adjusted.
|
* @param max_message_size With this parameter, the maximum message size can be adjusted.
|
||||||
* This should be left default.
|
* This should be left default.
|
||||||
*/
|
*/
|
||||||
MessageQueue(size_t message_depth = 3,
|
explicit 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);
|
MqArgs* args = nullptr);
|
||||||
|
|
||||||
@ -48,18 +48,19 @@ class MessageQueue : public MessageQueueBase {
|
|||||||
* @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();
|
~MessageQueue() override;
|
||||||
|
|
||||||
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
// Implement non-generic MessageQueueIF functions not handled by MessageQueueBase
|
||||||
ReturnValue_t flush(uint32_t* count) override;
|
ReturnValue_t flush(uint32_t* count) override;
|
||||||
|
|
||||||
|
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
|
||||||
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
ReturnValue_t sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessageIF* message,
|
||||||
MessageQueueId_t sentFrom = NO_QUEUE,
|
MessageQueueId_t sentFrom, bool ignoreFault) override;
|
||||||
bool ignoreFault = false) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* \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
|
||||||
* reference is set by lazy loading
|
* reference is set by lazy loading
|
||||||
*/
|
*/
|
||||||
InternalErrorReporterIF* internalErrorReporter;
|
InternalErrorReporterIF* internalErrorReporter;
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack,
|
PeriodicTask::PeriodicTask(const char* name, rtems_task_priority setPriority, size_t setStack,
|
||||||
rtems_interval setPeriod, void (*setDeadlineMissedFunc)())
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc_)
|
||||||
: RTEMSTaskBase(setPriority, setStack, name),
|
: PeriodicTaskBase(setPeriod, dlmFunc_),
|
||||||
periodTicks(RtemsBasic::convertMsToTicks(setPeriod)),
|
RTEMSTaskBase(setPriority, setStack, name),
|
||||||
deadlineMissedFunc(setDeadlineMissedFunc) {}
|
periodTicks(RtemsBasic::convertMsToTicks(static_cast<uint32_t>(setPeriod * 1000.0))) {}
|
||||||
|
|
||||||
PeriodicTask::~PeriodicTask(void) {
|
PeriodicTask::~PeriodicTask() {
|
||||||
/* Do not delete objects, we were responsible for pointers only. */
|
/* Do not delete objects, we were responsible for pointers only. */
|
||||||
rtems_rate_monotonic_delete(periodId);
|
rtems_rate_monotonic_delete(periodId);
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ PeriodicTask::~PeriodicTask(void) {
|
|||||||
rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) {
|
rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) {
|
||||||
/* The argument is re-interpreted as MultiObjectTask. The Task object is global,
|
/* The argument is re-interpreted as MultiObjectTask. The Task object is global,
|
||||||
so it is found from any place. */
|
so it is found from any place. */
|
||||||
PeriodicTask* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
auto* originalTask(reinterpret_cast<PeriodicTask*>(argument));
|
||||||
return originalTask->taskFunctionality();
|
return originalTask->taskFunctionality();
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -28,8 +28,10 @@ ReturnValue_t PeriodicTask::startTask() {
|
|||||||
rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this));
|
rtems_task_start(id, PeriodicTask::taskEntryPoint, rtems_task_argument((void*)this));
|
||||||
if (status != RTEMS_SUCCESSFUL) {
|
if (status != RTEMS_SUCCESSFUL) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "ObjectTask::startTask for " << std::hex << this->getId() << std::dec
|
sif::error << "PeriodicTask::startTask for " << std::hex << this->getId() << std::dec
|
||||||
<< " failed." << std::endl;
|
<< " failed" << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("PeriodicTask::startTask for 0x%08x failed\n", getId());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -47,38 +49,20 @@ ReturnValue_t PeriodicTask::startTask() {
|
|||||||
|
|
||||||
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); }
|
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { return RTEMSTaskBase::sleepFor(ms); }
|
||||||
|
|
||||||
void PeriodicTask::taskFunctionality() {
|
[[noreturn]] void PeriodicTask::taskFunctionality() {
|
||||||
RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId);
|
RTEMSTaskBase::setAndStartPeriod(periodTicks, &periodId);
|
||||||
for (const auto& object : objectList) {
|
initObjsAfterTaskCreation();
|
||||||
object->initializeAfterTaskCreation();
|
|
||||||
}
|
|
||||||
/* The task's "infinite" inner loop is entered. */
|
/* The task's "infinite" inner loop is entered. */
|
||||||
while (1) {
|
while (true) {
|
||||||
for (const auto& object : objectList) {
|
for (const auto& objectPair : objectList) {
|
||||||
object->performOperation();
|
objectPair.first->performOperation(objectPair.second);
|
||||||
}
|
}
|
||||||
rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId);
|
rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks, periodId);
|
||||||
if (status == RTEMS_TIMEOUT) {
|
if (status == RTEMS_TIMEOUT) {
|
||||||
if (this->deadlineMissedFunc != nullptr) {
|
if (dlmFunc != nullptr) {
|
||||||
this->deadlineMissedFunc();
|
dlmFunc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
|
|
||||||
ExecutableObjectIF* newObject = ObjectManager::instance()->get<ExecutableObjectIF>(object);
|
|
||||||
return addComponent(newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t PeriodicTask::addComponent(ExecutableObjectIF* object) {
|
|
||||||
if (object == nullptr) {
|
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
|
||||||
}
|
|
||||||
objectList.push_back(object);
|
|
||||||
object->setTaskIF(this);
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PeriodicTask::getPeriodMs() const { return RtemsBasic::convertTicksToMs(periodTicks); }
|
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../../objectmanager/ObjectManagerIF.h"
|
|
||||||
#include "../../tasks/PeriodicTaskIF.h"
|
|
||||||
#include "RTEMSTaskBase.h"
|
#include "RTEMSTaskBase.h"
|
||||||
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
|
||||||
class ExecutableObjectIF;
|
class ExecutableObjectIF;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ class ExecutableObjectIF;
|
|||||||
* @author baetz
|
* @author baetz
|
||||||
* @ingroup task_handling
|
* @ingroup task_handling
|
||||||
*/
|
*/
|
||||||
class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
class PeriodicTask : public PeriodicTaskBase, public RTEMSTaskBase {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Standard constructor of the class.
|
* @brief Standard constructor of the class.
|
||||||
@ -36,12 +37,12 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
|||||||
* that shall be assigned.
|
* that shall be assigned.
|
||||||
*/
|
*/
|
||||||
PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack,
|
PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack,
|
||||||
rtems_interval setPeriod, void (*setDeadlineMissedFunc)());
|
TaskPeriod setPeriod, TaskDeadlineMissedFunction dlmFunc);
|
||||||
/**
|
/**
|
||||||
* @brief Currently, the executed object's lifetime is not coupled with the task object's
|
* @brief Currently, the executed object's lifetime is not coupled with the task object's
|
||||||
* lifetime, so the destructor is empty.
|
* lifetime, so the destructor is empty.
|
||||||
*/
|
*/
|
||||||
virtual ~PeriodicTask(void);
|
~PeriodicTask() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The method to start the task.
|
* @brief The method to start the task.
|
||||||
@ -50,33 +51,11 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
|||||||
* The address of the task object is passed as an argument
|
* The address of the task object is passed as an argument
|
||||||
* to the system call.
|
* to the system call.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t startTask(void);
|
ReturnValue_t startTask() 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 RETURN_OK on success, RETURN_FAILED if the object could not be added.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms) override;
|
ReturnValue_t sleepFor(uint32_t ms) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::vector<ExecutableObjectIF *> ObjectList; //!< Typedef for the List of objects.
|
|
||||||
/**
|
|
||||||
* @brief This attribute holds a list of objects to be executed.
|
|
||||||
*/
|
|
||||||
ObjectList objectList;
|
|
||||||
/**
|
/**
|
||||||
* @brief The period of the task.
|
* @brief The period of the task.
|
||||||
* @details The period determines the frequency of the task's execution. It is expressed in
|
* @details The period determines the frequency of the task's execution. It is expressed in
|
||||||
@ -87,14 +66,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
|||||||
* @brief id of the associated OS period
|
* @brief id of the associated OS period
|
||||||
*/
|
*/
|
||||||
rtems_id periodId = 0;
|
rtems_id periodId = 0;
|
||||||
/**
|
|
||||||
* @brief The pointer to the deadline-missed function.
|
|
||||||
* @details This pointer stores the function that is executed if the task's deadline is missed.
|
|
||||||
* So, each may react individually on a timing failure. The pointer may be
|
|
||||||
* nullptr, then nothing happens on missing the deadline. The deadline is equal to the next
|
|
||||||
* execution of the periodic task.
|
|
||||||
*/
|
|
||||||
void (*deadlineMissedFunc)(void);
|
|
||||||
/**
|
/**
|
||||||
* @brief This is the function executed in the new task's context.
|
* @brief This is the function executed in the new task's context.
|
||||||
* @details It converts the argument back to the thread object type and copies the class
|
* @details It converts the argument back to the thread object type and copies the class
|
||||||
@ -110,7 +82,7 @@ class PeriodicTask : public RTEMSTaskBase, public PeriodicTaskIF {
|
|||||||
* are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next
|
* are called. Afterwards the checkAndRestartPeriod system call blocks the task until the next
|
||||||
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
* period. On missing the deadline, the deadlineMissedFunction is executed.
|
||||||
*/
|
*/
|
||||||
void taskFunctionality(void);
|
[[noreturn]] void taskFunctionality();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */
|
#endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */
|
||||||
|
@ -45,9 +45,9 @@ QueueFactory* QueueFactory::instance() {
|
|||||||
return factoryInstance;
|
return factoryInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueFactory::QueueFactory() {}
|
QueueFactory::QueueFactory() = default;
|
||||||
|
|
||||||
QueueFactory::~QueueFactory() {}
|
QueueFactory::~QueueFactory() = default;
|
||||||
|
|
||||||
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, size_t maxMessageSize,
|
||||||
MqArgs* args) {
|
MqArgs* args) {
|
||||||
|
@ -32,7 +32,7 @@ RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size
|
|||||||
|
|
||||||
RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); }
|
RTEMSTaskBase::~RTEMSTaskBase() { rtems_task_delete(id); }
|
||||||
|
|
||||||
rtems_id RTEMSTaskBase::getId() { return this->id; }
|
rtems_id RTEMSTaskBase::getId() const { return this->id; }
|
||||||
|
|
||||||
ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
|
ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
|
||||||
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
|
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
|
||||||
|
@ -36,9 +36,9 @@ class RTEMSTaskBase {
|
|||||||
/**
|
/**
|
||||||
* @brief This method returns the task id of this class.
|
* @brief This method returns the task id of this class.
|
||||||
*/
|
*/
|
||||||
rtems_id getId();
|
rtems_id getId() const;
|
||||||
|
|
||||||
ReturnValue_t sleepFor(uint32_t ms);
|
static ReturnValue_t sleepFor(uint32_t ms);
|
||||||
static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId);
|
static ReturnValue_t setAndStartPeriod(rtems_interval period, rtems_id *periodId);
|
||||||
static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId);
|
static rtems_status_code restartPeriod(rtems_interval period, rtems_id periodId);
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "fsfw/tasks/TaskFactory.h"
|
#include "fsfw/tasks/TaskFactory.h"
|
||||||
|
|
||||||
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
|
#include "fsfw/osal/rtems/FixedTimeslotTask.h"
|
||||||
#include "fsfw/osal/rtems/InitTask.h"
|
|
||||||
#include "fsfw/osal/rtems/PeriodicTask.h"
|
#include "fsfw/osal/rtems/PeriodicTask.h"
|
||||||
#include "fsfw/osal/rtems/RtemsBasic.h"
|
#include "fsfw/osal/rtems/RtemsBasic.h"
|
||||||
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
|
||||||
@ -9,29 +8,29 @@
|
|||||||
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
// TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
|
||||||
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
|
||||||
|
|
||||||
TaskFactory::~TaskFactory() {}
|
TaskFactory::TaskFactory() = default;
|
||||||
|
|
||||||
|
TaskFactory::~TaskFactory() = default;
|
||||||
|
|
||||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||||
|
|
||||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||||
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
|
return static_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_, stackSize_,
|
||||||
|
periodInSeconds_, deadLineMissedFunction_));
|
||||||
return static_cast<PeriodicTaskIF*>(
|
|
||||||
new PeriodicTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||||
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
|
return static_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(
|
||||||
return static_cast<FixedTimeslotTaskIF*>(
|
name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_));
|
||||||
new FixedTimeslotTask(name_, taskPriority_, stackSize_, taskPeriod, deadLineMissedFunction_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||||
// TODO not implemented
|
// This should call the OS specific destructor
|
||||||
|
delete (dynamic_cast<PeriodicTask*>(task));
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,5 +44,3 @@ void TaskFactory::printMissedDeadline() {
|
|||||||
/* TODO: Implement */
|
/* TODO: Implement */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskFactory::TaskFactory() {}
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user