Compare commits
335 Commits
mohr/dhb2n
...
move_seman
Author | SHA1 | Date | |
---|---|---|---|
6fa453940f | |||
9a8d775eb1 | |||
4d6f6e6b23 | |||
55f6825a03 | |||
c162acb7df | |||
87462afe6d | |||
a8de395ea0 | |||
f0bddfcb21 | |||
23d9b44b3e | |||
26e4445189 | |||
9ee3cdf729 | |||
1b7493f945 | |||
7f6ba5f40b | |||
070b48ada2 | |||
d9a139e1ef | |||
c80a3752d9 | |||
af58c414fc | |||
4c48668125 | |||
2745b2080d | |||
e9d9f44605 | |||
2c5af91db1 | |||
5cd7b98ba7 | |||
a39f1271ec | |||
bbf0d7a0d2 | |||
04ee3c7362 | |||
95dab69b35 | |||
33de15205b | |||
4d353a1ad2 | |||
6006c97e48 | |||
6e17e45506 | |||
64537d442a | |||
78cf00315d | |||
245886c555 | |||
f84097543e | |||
511d07c0c7 | |||
cf735143fe | |||
bdfe31dba4 | |||
216f603d62 | |||
174a6aa862 | |||
c2d9370aa1 | |||
893b434728 | |||
6eba84566d | |||
f0415a97b1 | |||
abcf1b29b2 | |||
d373c45d36 | |||
bd208038dd | |||
206af00c8b | |||
2efff4d2c5 | |||
2a0c244468 | |||
e1711f0345 | |||
c327985222 | |||
b45206ccd6 | |||
c8469ca647 | |||
2d6622b8b8 | |||
5f9eb01d94 | |||
3568bdbecf | |||
fcd84b59ae | |||
e3c968096b | |||
c745c0c8b4 | |||
be015b4c66 | |||
dae5e988fd | |||
a6d707a7db | |||
fe41d73895 | |||
70b785984c | |||
9de6c4b3aa | |||
d256ede8c1 | |||
f0b8457ba2 | |||
dac2d210b5 | |||
8b4f73a97b | |||
7fae6cbd6d | |||
d302ba7185 | |||
14a92b3d89 | |||
e4fd424d66 | |||
341a66c265 | |||
b9b076aa4c | |||
d93486a340 | |||
820a7f059c | |||
f4d188c36f | |||
1841f92944 | |||
b279985859 | |||
fa7675897d | |||
3a2393885f | |||
c752b6d143 | |||
b676040c7c | |||
010509efb4 | |||
dfb1633f00 | |||
5f7172e130 | |||
0c6465cd95 | |||
f94987c46d | |||
1809ce359b | |||
8c712441ab | |||
6ce80ea6c5 | |||
f1b0ca7cff | |||
000df85556 | |||
1fffcc2229 | |||
6f05d6b7b0 | |||
7f907fb9d3 | |||
a419806a05 | |||
84bbef0167 | |||
88b2b0e005 | |||
6445debfa1 | |||
8014e4adf9 | |||
84dc7ac0ce | |||
ec12ab5daa | |||
134d908f26 | |||
40a9e12416 | |||
f39054edd4 | |||
5adf89b911 | |||
c2e6a22dec | |||
c8e065a713 | |||
69c94645df | |||
37e850c5a7 | |||
3ed49dbae3 | |||
a1567de9e8 | |||
4cf52d5dfe | |||
2646707d3f | |||
539d7aac9e | |||
0a23f2c85a | |||
06e30684fe | |||
46230e6c6d | |||
b22d439300 | |||
7e7b3bbbc9 | |||
06dca7608a | |||
6af5274b68 | |||
e2b66df72e | |||
7b828f233a | |||
c3d1000cd5 | |||
8e0e57714d | |||
cc9e54ea6b | |||
31465a4e0f | |||
c0e5d1eb99 | |||
3bc5d4a2e0 | |||
b1e9dd9e4a | |||
ab86599db3 | |||
034eb34c2e | |||
38789e053b | |||
4374c7c4f4 | |||
5343844be5 | |||
e11eabdbcf | |||
3250bbf269 | |||
a78fe0a7f3 | |||
acfc1cbf21 | |||
d17ec02cf0 | |||
e300490b93 | |||
f2461cd7e9 | |||
01cc619e67 | |||
0f811777a7 | |||
e93137939e | |||
2339712373 | |||
d9d253d3bb | |||
bd586f6564 | |||
1f88c006d9 | |||
5f481739d8 | |||
7e94baceef | |||
7ee83e4e5d | |||
64787f85ca | |||
1cacceddad | |||
5c35b8e3cd | |||
9b05e8f274 | |||
7766b24a1d | |||
eb223dae88 | |||
3656662d88 | |||
fe71978467 | |||
b646717a76 | |||
99d8c845f2 | |||
9a4ae550ab | |||
c64b9b3e71 | |||
226818886f | |||
da12495335 | |||
0cc3231ceb | |||
049e3b431d | |||
bd189518b6 | |||
0e7c6b117f | |||
accaf855ee | |||
75fa7caf25 | |||
d16c5024dc | |||
a4531e4ced | |||
97c629ad84 | |||
bf12f284fa | |||
ba62c28b64 | |||
041d1b8795 | |||
7adb47aecb | |||
5bb66c9723 | |||
8589f4d63a | |||
ca80589233 | |||
f2ebaed092 | |||
f0b89e98df | |||
2aa4af6974 | |||
75fc7a056d | |||
05cad893a2 | |||
5557d95994 | |||
fc24c9b5d8 | |||
1b005d706a | |||
5b0ea91222 | |||
7ef69c839c | |||
9b798d798e | |||
e68f54b9bd | |||
8eb869e073 | |||
b13453f46b | |||
d0e322d7e2 | |||
46a1c2bace | |||
2643ff194c | |||
ecde164f68 | |||
50930b41ba | |||
296bc56e2a | |||
d6ee2ed400 | |||
f2150ff9c2 | |||
1b9c98f3fe | |||
742152b28e | |||
bf4ca56658 | |||
16ffa00155 | |||
14c681c93a | |||
0958c3a00e | |||
d699d16307 | |||
3b0fed733f | |||
23d3812fe3 | |||
dec7db3ae2 | |||
65a5abab49 | |||
0129783e34 | |||
cabe0868ec | |||
f05295bada | |||
160ff799ac | |||
b85ca64690 | |||
3bc3da5a8d | |||
f8c07ec9cf | |||
8199b8f359 | |||
cbc8dbcdd4 | |||
d31a5306f0 | |||
a236a5ec50 | |||
03620970e2 | |||
8fe8d810e9 | |||
9483c2809d | |||
fe3d6bd432 | |||
c5f91926c9 | |||
be4a87535d | |||
99927b8e95 | |||
5e5eb82830 | |||
686dc97234 | |||
2a842666d5 | |||
c013fcc1f5 | |||
1f58ba1f9b | |||
002845108d | |||
1b8fc2af19 | |||
72d7c43445 | |||
ab9b6c8c89 | |||
69d338f9bb | |||
68223869d5 | |||
93fda71989 | |||
7b0db08962 | |||
0956fbc740 | |||
b48e0fdc0d | |||
1d084ee22f | |||
1bea2344f6 | |||
d7e16a67a7 | |||
6021d897b8 | |||
83a6f0b5f8 | |||
a9c6c088f2 | |||
2b6a33e718 | |||
61fd5d1b62 | |||
046dbe1deb | |||
e03e7f5260 | |||
b6a3c206cc | |||
5b352978c5 | |||
0303c1a885 | |||
4d2802a470 | |||
819a298b19 | |||
39946bff58 | |||
16246d6ece | |||
5c84f12440 | |||
2a203ae13d | |||
6ca1a5c796 | |||
83c2c4825c | |||
194b3e100a | |||
177c39dd53 | |||
530a261e14 | |||
c913fe40bf | |||
70ec08bf1d | |||
ef23665d9c | |||
eefc122292 | |||
bee33526a1 | |||
0e8f5ddd26 | |||
672fca5169 | |||
84b9d1ce21 | |||
e5b5c7d253 | |||
9a0cc64be3 | |||
00f1c5bbe9 | |||
8a61af779d | |||
6efa482eb0 | |||
f0fa1bf477 | |||
91ebf98c28 | |||
e1d4209fbe | |||
e302c89f74 | |||
a38279f813 | |||
7600ed1ea7 | |||
61ab770d9d | |||
f715b65d6e | |||
c11af63015 | |||
852f27cec2 | |||
fa01798ebb | |||
819a2bfac4 | |||
dc1583c932 | |||
81a7de2814 | |||
d26f230bee | |||
4db124c680 | |||
2df66c9304 | |||
54ad6b3016 | |||
73e313c35b | |||
dd2f42d22b | |||
096af44e39 | |||
56e8e5a8b3 | |||
11422a658c | |||
ec7566fb8c | |||
652c31a683 | |||
bfe120636c | |||
a8041f220f | |||
dd636b186b | |||
3349fc36f8 | |||
df06064df0 | |||
1d6ccfe5ab | |||
221df7ece6 | |||
7f180ac1fa | |||
1eceef4645 | |||
acab5f6bce | |||
10dd855244 | |||
f824004897 | |||
7c5308429c | |||
f78344b8fb | |||
77f7fa2ef1 | |||
78314ad966 | |||
e0c780f21c | |||
876815b1c9 | |||
b0ecf87580 | |||
68ce8b5b08 | |||
fe03da6def | |||
4f7f8310c9 |
81
CHANGELOG.md
81
CHANGELOG.md
@ -12,6 +12,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Fixes
|
||||
|
||||
- Add monotonic watchdog Clock API and use it in `Countdown` and `Stopwatch` class.
|
||||
- Bugfix in `Service11TelecommandScheduling` which allowed commands
|
||||
time tagged in the past to be inserted.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/738
|
||||
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
|
||||
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
|
||||
subservice not working properly.
|
||||
- Memory leak fixes for the TCP/IP TMTC bridge.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
|
||||
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
|
||||
seconds instead of uptime.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
|
||||
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
|
||||
only the X scaling factor was used.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
|
||||
- Bugfix for RM3100 MGM sensors. Z value was previously calculated
|
||||
with bytes of the X value.
|
||||
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||
to false correctly because the `read` and `write` calls were missing.
|
||||
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||
of the correct unsegmented flags (0b11) as specified in the standard.
|
||||
- TC Scheduler Service 11: Add size and CRC check for contained TC.
|
||||
- Only delete health table entry in `HealthHelper` destructor if
|
||||
health table was set.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
|
||||
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
|
||||
Also properly reset the reply size for successfull transfers and erroneous transfers.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
|
||||
@ -24,19 +49,33 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Added
|
||||
|
||||
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
|
||||
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
|
||||
types of telemetry.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
|
||||
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
|
||||
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
|
||||
pointer.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
|
||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
|
||||
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
|
||||
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
||||
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
|
||||
option on the TCP server. CTOR prototype has changed and expects an explicit
|
||||
TCP configuration struct to be passed.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
|
||||
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
||||
- `UioMapper` is able to resolve symlinks now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||
- Add new `UnsignedByteField` class
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
||||
|
||||
## Changes
|
||||
|
||||
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
||||
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
||||
`HealthServiceCfg` now
|
||||
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
|
||||
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
||||
- Moved some container returnvalues to dedicated header and namespace
|
||||
to they can be used without template specification.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
|
||||
- Remove default secondary header argument for
|
||||
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
|
||||
`uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)`
|
||||
@ -65,6 +104,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||
interface itself so it can be re-used more easily. Also add new
|
||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||
- Make functions `const` where it makes sense
|
||||
- Add `const char* getName const` abstract function
|
||||
@ -92,6 +135,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
implementation without an extra component
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
|
||||
|
||||
## HAL
|
||||
|
||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||
differing speeds and modes are attached to one bus.
|
||||
- SPI: Getter functions for SPI speed and mode.
|
||||
|
||||
# [v5.0.0] 25.07.2022
|
||||
|
||||
## Changes
|
||||
@ -225,6 +278,7 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||
Easiest solution for now: Keep this option OFF by default.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||
inside `fsfw/version.h`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||
@ -239,17 +293,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||
- `Subsystem`: New API to add table and sequence entries
|
||||
|
||||
## HAL
|
||||
|
||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||
differing speeds and modes are attached to one bus.
|
||||
- SPI: Getter functions for SPI speed and mode.
|
||||
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
||||
|
||||
## Fixed
|
||||
|
||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||
|
@ -122,6 +122,7 @@ if(UNIX)
|
||||
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
|
||||
OFF)
|
||||
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
|
||||
option(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS "Add serial drivers" ON)
|
||||
endif()
|
||||
|
||||
# Optional sources
|
||||
@ -152,12 +153,12 @@ if(FSFW_BUILD_TESTS)
|
||||
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||
)
|
||||
# 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} QUIET)
|
||||
# Not installed, so use FetchContent to download and provide Catch2
|
||||
if(NOT Catch2_FOUND)
|
||||
message(
|
||||
STATUS
|
||||
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent"
|
||||
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent."
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
@ -195,13 +196,13 @@ message(
|
||||
)
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||
# Not installed, so use FetchContent to download and provide etl
|
||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
message(
|
||||
STATUS
|
||||
"${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
|
||||
"etl with FindPackage")
|
||||
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
|
||||
)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
|
96
automation/Jenkinsfile
vendored
96
automation/Jenkinsfile
vendored
@ -1,45 +1,87 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILDDIR = 'cmake-build-tests'
|
||||
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||
DOCDDIR = 'cmake-build-documentation'
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'fsfw-ci:d6'
|
||||
args '--network host'
|
||||
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR'
|
||||
}
|
||||
}
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
stage('Host') {
|
||||
stages{
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR_HOST'
|
||||
}
|
||||
}
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake --build . -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -j4'
|
||||
stage('Linux') {
|
||||
stages{
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR_LINUX'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake --build . -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
|
||||
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
|
||||
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
|
||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( GCOVR_PATH gcovr )
|
||||
find_program( CPPFILT_PATH NAMES c++filt )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
|
@ -51,7 +51,10 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_theme_options = {
|
||||
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||
"extra_nav_links": {
|
||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -178,16 +178,25 @@ ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info)
|
||||
dp.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
}
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "File write error" << std::endl;
|
||||
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
||||
<< result << std::endl;
|
||||
#endif
|
||||
tp.vfsErrorCount++;
|
||||
if (tp.vfsErrorCount < 3) {
|
||||
// TODO: Provide execution step as parameter
|
||||
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
|
||||
result);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
tp.vfsErrorCount = 0;
|
||||
}
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -271,35 +280,55 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
size_t sourceNameSize = 0;
|
||||
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize > tp.sourceName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
if (sourceNameSize + 1 > tp.sourceName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize > tp.destName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
if (destNameSize + 1 > tp.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
||||
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// handling to allow only specifying target directory. Example:
|
||||
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
||||
if (dp.user.vfs.isDirectory(tp.destName.data())) {
|
||||
result = tryBuildingAbsoluteDestName(destNameSize);
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
result = dp.user.vfs.truncateFile(fparams);
|
||||
if (result != returnvalue::OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
||||
return FAILED;
|
||||
// TODO: Relevant for filestore rejection error?
|
||||
}
|
||||
}
|
||||
}
|
||||
EntityId sourceId;
|
||||
reader.getSourceId(sourceId);
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
|
||||
// TODO: Warning, event etc.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler" << __func__
|
||||
@ -308,22 +337,18 @@ ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, Met
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// TODO: Filesystem errors?
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
dp.user.vfs.truncateFile(fparams);
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
|
||||
// CFDP.
|
||||
// In any case, it does not really make sense to continue here
|
||||
}
|
||||
}
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||
params.fileSize = tp.fileSize.getSize();
|
||||
@ -362,6 +387,37 @@ ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
||||
char baseNameBuf[tp.destName.size()]{};
|
||||
FilesystemParams fparamsSrc(tp.sourceName.data());
|
||||
size_t baseNameLen = 0;
|
||||
ReturnValue_t result =
|
||||
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
|
||||
if (result != returnvalue::OK or baseNameLen == 0) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
|
||||
return FAILED;
|
||||
}
|
||||
// Destination name + slash + base name + null termination
|
||||
if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) {
|
||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
||||
"dest filename too large after adding source base name");
|
||||
return FAILED;
|
||||
}
|
||||
tp.destName[destNameSize++] = '/';
|
||||
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
||||
destNameSize += baseNameLen;
|
||||
tp.destName[destNameSize++] = '\0';
|
||||
return OK;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
|
||||
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
|
||||
static_cast<uint8_t>(fsmRes.step), result);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::finish() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
|
@ -84,7 +84,7 @@ enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep {
|
||||
enum class TransactionStep : uint8_t {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
@ -157,11 +157,13 @@ class DestHandler {
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
closureRequested = false;
|
||||
vfsErrorCount = 0;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
uint16_t vfsErrorCount = 0;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
@ -189,9 +191,11 @@ class DestHandler {
|
||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
||||
size_t maxSize);
|
||||
ReturnValue_t handleTransferCompletion();
|
||||
ReturnValue_t tryBuildingAbsoluteDestName(size_t destNameSize);
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
|
@ -12,6 +12,9 @@ namespace events {
|
||||
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
|
||||
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
||||
|
||||
} // namespace events
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../serialize/SerializeAdapter.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief A List that stores its values in an array.
|
||||
@ -19,9 +20,6 @@ class ArrayList {
|
||||
friend class SerialArrayListAdapter;
|
||||
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
|
||||
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
|
||||
|
||||
/**
|
||||
* This is the allocating constructor.
|
||||
* It allocates an array of the specified size.
|
||||
@ -187,7 +185,7 @@ class ArrayList {
|
||||
*/
|
||||
ReturnValue_t insert(T entry) {
|
||||
if (size >= maxSize_) {
|
||||
return FULL;
|
||||
return containers::LIST_FULL;
|
||||
}
|
||||
entries[size] = entry;
|
||||
++size;
|
||||
|
@ -12,6 +12,7 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||
class FixedArrayList : public ArrayList<T, count_t> {
|
||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||
"count_t is not large enough to hold MAX_SIZE");
|
||||
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
|
||||
|
||||
private:
|
||||
T data[MAX_SIZE];
|
||||
@ -20,15 +21,19 @@ class FixedArrayList : public ArrayList<T, count_t> {
|
||||
FixedArrayList() : ArrayList<T, count_t>(data, MAX_SIZE) {}
|
||||
|
||||
FixedArrayList(const FixedArrayList& other) : ArrayList<T, count_t>(data, MAX_SIZE) {
|
||||
memcpy(this->data, other.data, sizeof(this->data));
|
||||
this->entries = data;
|
||||
this->size = other.size;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
}
|
||||
|
||||
FixedArrayList& operator=(FixedArrayList other) {
|
||||
memcpy(this->data, other.data, sizeof(this->data));
|
||||
this->entries = data;
|
||||
this->size = other.size;
|
||||
for (size_t idx = 0; idx < this->size; idx++) {
|
||||
data[idx] = other.data[idx];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "ArrayList.h"
|
||||
#include "definitions.h"
|
||||
|
||||
/**
|
||||
* @brief Map implementation for maps with a pre-defined size.
|
||||
@ -24,11 +24,6 @@ class FixedMap : public SerializeIF {
|
||||
"derived class from SerializeIF to be serialize-able");
|
||||
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
|
||||
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
|
||||
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
|
||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
|
||||
|
||||
private:
|
||||
static const key_t EMPTY_SLOT = -1;
|
||||
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
|
||||
@ -76,10 +71,10 @@ class FixedMap : public SerializeIF {
|
||||
|
||||
ReturnValue_t insert(key_t key, T value, Iterator* storedValue = nullptr) {
|
||||
if (exists(key) == returnvalue::OK) {
|
||||
return KEY_ALREADY_EXISTS;
|
||||
return containers::KEY_ALREADY_EXISTS;
|
||||
}
|
||||
if (_size == theMap.maxSize()) {
|
||||
return MAP_FULL;
|
||||
return containers::MAP_FULL;
|
||||
}
|
||||
theMap[_size].first = key;
|
||||
theMap[_size].second = value;
|
||||
@ -93,7 +88,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t insert(std::pair<key_t, T> pair) { return insert(pair.first, pair.second); }
|
||||
|
||||
ReturnValue_t exists(key_t key) const {
|
||||
ReturnValue_t result = KEY_DOES_NOT_EXIST;
|
||||
ReturnValue_t result = containers::KEY_DOES_NOT_EXIST;
|
||||
if (findIndex(key) < _size) {
|
||||
result = returnvalue::OK;
|
||||
}
|
||||
@ -103,7 +98,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(Iterator* iter) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex((*iter).value->first)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
@ -114,7 +109,7 @@ class FixedMap : public SerializeIF {
|
||||
ReturnValue_t erase(key_t key) {
|
||||
uint32_t i;
|
||||
if ((i = findIndex(key)) >= _size) {
|
||||
return KEY_DOES_NOT_EXIST;
|
||||
return containers::KEY_DOES_NOT_EXIST;
|
||||
}
|
||||
theMap[i] = theMap[_size - 1];
|
||||
--_size;
|
||||
|
14
src/fsfw/container/definitions.h
Normal file
14
src/fsfw/container/definitions.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_CONTAINER_DEFINITIONS_H_
|
||||
#define FSFW_CONTAINER_DEFINITIONS_H_
|
||||
|
||||
#include "fsfw/retval.h"
|
||||
|
||||
namespace containers {
|
||||
static const ReturnValue_t KEY_ALREADY_EXISTS = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x01);
|
||||
static const ReturnValue_t MAP_FULL = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x02);
|
||||
static const ReturnValue_t KEY_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x03);
|
||||
|
||||
static const ReturnValue_t LIST_FULL = returnvalue::makeCode(CLASS_ID::ARRAY_LIST, 0x01);
|
||||
} // namespace containers
|
||||
|
||||
#endif /* FSFW_CONTAINER_DEFINITIONS_H_ */
|
@ -4,11 +4,10 @@
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, size_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
parentId(parentId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
@ -21,33 +20,15 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t ControllerBase::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
@ -120,3 +101,13 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||
|
||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
||||
|
||||
const HasHealthIF* ControllerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& ControllerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/modes/ModeHelper.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
@ -18,13 +21,18 @@
|
||||
class ControllerBase : public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
|
||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ControllerBase(object_id_t setObjectId, size_t commandQueueDepth = 3);
|
||||
~ControllerBase() override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/** SystemObject override */
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -38,6 +46,8 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
void setTaskIF(PeriodicTaskIF *task) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -56,8 +66,6 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
Mode_t mode;
|
||||
|
||||
Submode_t submode;
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include "fsfw/controller/ExtendedControllerBase.h"
|
||||
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, parentId, commandQueueDepth),
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, commandQueueDepth),
|
||||
poolManager(this, commandQueue),
|
||||
actionHelper(this, commandQueue) {}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
public HasActionsIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth = 3);
|
||||
~ExtendedControllerBase() override;
|
||||
|
||||
/* SystemObjectIF overrides */
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE),
|
||||
recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()),
|
||||
|
@ -41,7 +41,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
||||
|
||||
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||
AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth = 8);
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
|
@ -3,17 +3,12 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
||||
CookieIF* cookie, object_id_t hkDestination,
|
||||
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||
object_id_t parent, FailureIsolationBase* customFdir,
|
||||
size_t cmdQueueSize)
|
||||
CookieIF* cookie, HasModeTreeChildrenIF& parent,
|
||||
FailureIsolationBase* customFdir, size_t cmdQueueSize)
|
||||
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
||||
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
||||
parentId(parent),
|
||||
childHandlerFdir(setObjectId) {
|
||||
this->setHkDestination(hkDestination);
|
||||
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
|
||||
}
|
||||
parent(parent),
|
||||
childHandlerFdir(setObjectId) {}
|
||||
|
||||
ChildHandlerBase::~ChildHandlerBase() {}
|
||||
|
||||
@ -23,21 +18,5 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
healthHelper.setParentQueue(parentQueue);
|
||||
|
||||
modeHelper.setParentQueue(parentQueue);
|
||||
|
||||
return returnvalue::OK;
|
||||
return DeviceHandlerBase::connectModeTreeParent(parent);
|
||||
}
|
||||
|
@ -1,22 +1,23 @@
|
||||
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
|
||||
#include <fsfw/subsystem/HasModeTreeChildrenIF.h>
|
||||
|
||||
#include "ChildHandlerFDIR.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
class ChildHandlerBase : public DeviceHandlerBase {
|
||||
public:
|
||||
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
||||
object_id_t hkDestination, uint32_t thermalStatePoolId,
|
||||
uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT,
|
||||
FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20);
|
||||
HasModeTreeChildrenIF& parent, FailureIsolationBase* customFdir = nullptr,
|
||||
size_t cmdQueueSize = 20);
|
||||
|
||||
virtual ~ChildHandlerBase();
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
const uint32_t parentId;
|
||||
HasModeTreeChildrenIF& parent;
|
||||
ChildHandlerFDIR childHandlerFdir;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
#include "fsfw/datapool/PoolReadGuard.h"
|
||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
|
||||
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
|
||||
@ -12,6 +13,7 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||
|
||||
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
@ -56,12 +58,7 @@ void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
this->hkDestination = hkDestination;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId,
|
||||
lp_id_t heaterRequestPoolId,
|
||||
uint32_t thermalSetId) {
|
||||
thermalSet =
|
||||
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
|
||||
}
|
||||
void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; }
|
||||
|
||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||
if (comCookie != nullptr) {
|
||||
@ -132,14 +129,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
if (this->parent != objects::NO_OBJECT) {
|
||||
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
|
||||
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
|
||||
if (modeIF != nullptr and healthIF != nullptr) {
|
||||
setParentQueue(modeIF->getCommandQueue());
|
||||
}
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
if (communicationInterface == nullptr) {
|
||||
@ -233,12 +222,11 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
fillCommandAndReplyMap();
|
||||
|
||||
if (thermalSet != nullptr) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
// Set temperature target state to NON_OP.
|
||||
result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
thermalSet->commit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,6 +356,8 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) {
|
||||
// NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
|
||||
childTransitionFailure = CHILD_TIMEOUT;
|
||||
transitionSourceMode = _MODE_SHUT_DOWN;
|
||||
transitionSourceSubMode = SUBMODE_NONE;
|
||||
setMode(_MODE_START_UP);
|
||||
callChildStatemachine();
|
||||
}
|
||||
@ -386,7 +376,7 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
|
||||
setMode(_MODE_SWITCH_IS_OFF);
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
}
|
||||
} break;
|
||||
case MODE_OFF:
|
||||
@ -399,9 +389,6 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
case MODE_NORMAL:
|
||||
case MODE_ERROR_ON:
|
||||
break;
|
||||
case _MODE_SWITCH_IS_OFF:
|
||||
setMode(MODE_OFF, SUBMODE_NONE);
|
||||
break;
|
||||
default:
|
||||
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
|
||||
setMode(_MODE_POWER_DOWN, 0);
|
||||
@ -573,12 +560,14 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
|
||||
/**
|
||||
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
|
||||
*/
|
||||
if (newMode == MODE_ON and continueToNormal) {
|
||||
continueToNormal = false;
|
||||
// TODO: Check whether the following two lines are okay to do so.
|
||||
transitionSourceMode = MODE_ON;
|
||||
transitionSourceSubMode = submode;
|
||||
mode = _MODE_TO_NORMAL;
|
||||
return;
|
||||
}
|
||||
@ -599,12 +588,12 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
Clock::getUptime(&timeoutStart);
|
||||
|
||||
if (mode == MODE_OFF and thermalSet != nullptr) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||
}
|
||||
thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
|
||||
thermalSet->heaterRequest.setValid(true);
|
||||
}
|
||||
}
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
@ -1093,8 +1082,8 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
||||
// Do not check thermal state for MODE_RAW
|
||||
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
|
||||
(thermalSet != nullptr)) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
||||
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
||||
@ -1155,11 +1144,10 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
|
||||
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
|
||||
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
|
||||
if (thermalSet != nullptr) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
PoolReadGuard pg(thermalSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
||||
thermalSet->commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1482,11 +1470,11 @@ void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
LocalDataPoolManager& poolManager) {
|
||||
if (thermalSet != nullptr) {
|
||||
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
|
||||
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>);
|
||||
if (thermalStateCfg.has_value()) {
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>());
|
||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId,
|
||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>());
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -1499,6 +1487,10 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
}
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (thermalStateCfg.has_value()) {
|
||||
ThermalStateCfg& cfg = thermalStateCfg.value();
|
||||
thermalSet = new DeviceHandlerThermalSet(this, cfg);
|
||||
}
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
}
|
||||
@ -1530,7 +1522,10 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
|
||||
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
|
||||
for (const auto& reply : deviceReplyMap) {
|
||||
if (reply.second.dataSet != nullptr) {
|
||||
reply.second.dataSet->setValidity(false, true);
|
||||
PoolReadGuard pg(reply.second.dataSet);
|
||||
if (pg.getReadResult() == returnvalue::OK) {
|
||||
reply.second.dataSet->setValidity(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1587,19 +1582,13 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
||||
Mode_t DeviceHandlerBase::getMode() {
|
||||
return mode;
|
||||
}
|
||||
Mode_t DeviceHandlerBase::getMode() { return mode; }
|
||||
|
||||
Submode_t DeviceHandlerBase::getSubmode() {
|
||||
return submode;
|
||||
}
|
||||
Submode_t DeviceHandlerBase::getSubmode() { return submode; }
|
||||
|
||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
for (auto& command : deviceCommandMap) {
|
||||
@ -1619,6 +1608,16 @@ void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& DeviceHandlerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& DeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
||||
ReturnValue_t result) {
|
||||
auto commandIter = deviceCommandMap.find(action);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "DeviceCommunicationIF.h"
|
||||
#include "DeviceHandlerFailureIsolation.h"
|
||||
@ -21,9 +22,9 @@
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
#include "fsfw/util/dataWrapper.h"
|
||||
|
||||
namespace Factory {
|
||||
void setStaticFrameworkObjectIds();
|
||||
@ -84,6 +85,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasActionsIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ReceivesParameterMessagesIF,
|
||||
public HasLocalDataPoolIF {
|
||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||
@ -104,7 +107,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setParent(object_id_t parent);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
|
||||
/**
|
||||
@ -148,11 +150,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c _MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and is off now. This state is only to do an RMAP
|
||||
//! cycle once more where the doSendRead() function will set the mode to
|
||||
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
@ -162,13 +159,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* The device handler will then take care of creating local pool entries
|
||||
* for the device thermal state and device heating request.
|
||||
* Custom local pool IDs can be assigned as well.
|
||||
* @param thermalStatePoolId
|
||||
* @param thermalRequestPoolId
|
||||
*/
|
||||
void setThermalStateRequestPoolIds(
|
||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
|
||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
|
||||
void enableThermalModule(ThermalStateCfg cfg);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* @brief Helper function to ease device handler development.
|
||||
* This will instruct the transition to MODE_ON immediately
|
||||
@ -214,7 +210,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @param counter Specifies which Action to perform
|
||||
* @return returnvalue::OK for successful execution
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||
ReturnValue_t performOperation(uint8_t counter) override;
|
||||
|
||||
/**
|
||||
* @brief Initializes the device handler
|
||||
@ -224,14 +220,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Calls fillCommandAndReplyMap().
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief Intialization steps performed after all tasks have been created.
|
||||
* This function will be called by the executing task.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DeviceHandlerBase();
|
||||
@ -248,6 +244,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual object_id_t getObjectId() const override;
|
||||
|
||||
/**
|
||||
* This is a helper method for classes which are parent nodes in the mode tree.
|
||||
* It registers the passed queue as the destination for mode and health messages.
|
||||
* @param parentQueueId
|
||||
*/
|
||||
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
||||
@ -924,6 +922,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
//! Object which may be the root cause of an identified fault.
|
||||
static object_id_t defaultFdirParentId;
|
||||
|
||||
std::optional<ThermalStateCfg> thermalStateCfg;
|
||||
|
||||
/**
|
||||
* @brief Send a reply to a received device handler command.
|
||||
*
|
||||
@ -1012,6 +1012,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
LocalDataPoolManager *getHkManagerHandle() override;
|
||||
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
/**
|
||||
* Returns the delay cycle count of a reply.
|
||||
* A count != 0 indicates that the command is already executed.
|
||||
|
@ -136,4 +136,10 @@ class DeviceHandlerIF {
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
};
|
||||
|
||||
struct ThermalStateCfg {
|
||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID;
|
||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID;
|
||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */
|
||||
|
@ -7,27 +7,21 @@
|
||||
|
||||
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
||||
public:
|
||||
DeviceHandlerThermalSet(
|
||||
HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {}
|
||||
DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg)
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
|
||||
|
||||
DeviceHandlerThermalSet(
|
||||
object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||
lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, setId)),
|
||||
thermalStatePoolId(thermalStateId),
|
||||
heaterRequestPoolId(thermalStateRequestId) {}
|
||||
DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
|
||||
: StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)),
|
||||
thermalStatePoolId(cfg.thermalStatePoolId),
|
||||
heaterRequestPoolId(cfg.thermalRequestPoolId) {}
|
||||
|
||||
const lp_id_t thermalStatePoolId;
|
||||
const lp_id_t heaterRequestPoolId;
|
||||
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(thermalStatePoolId, sid.objectId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(sid.objectId, thermalStatePoolId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(heaterRequestPoolId, sid.objectId, this);
|
||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(sid.objectId, heaterRequestPoolId, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "fsfw/action/HasActionsIF.h"
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
#include "fsfw/util/dataWrapper.h"
|
||||
|
||||
class DeviceTmReportingWrapper : public SerializeIF {
|
||||
public:
|
||||
|
@ -15,15 +15,16 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
||||
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
|
||||
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
|
||||
|
||||
EventManager::EventManager(object_id_t setObjectId)
|
||||
EventManager::EventManager(object_id_t setObjectId, uint32_t eventQueueDepth)
|
||||
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
EventManager::~EventManager() {
|
||||
listenerList.clear();
|
||||
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
}
|
||||
@ -73,9 +74,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
|
||||
if (!result.second) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
|
||||
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
|
||||
return subscribeToEventRange(listener, event);
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ extern const char* translateEvents(Event event);
|
||||
|
||||
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
||||
public:
|
||||
static const uint16_t MAX_EVENTS_PER_CYCLE = 80;
|
||||
static const uint16_t DEFAULT_MAX_EVENTS_PER_CYCLE = 80;
|
||||
|
||||
EventManager(object_id_t setObjectId);
|
||||
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
|
||||
virtual ~EventManager();
|
||||
|
||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||
@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
||||
MessageQueueId_t getEventReportQueue();
|
||||
|
||||
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
|
||||
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
|
||||
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
|
||||
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
|
||||
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||
|
@ -18,6 +18,7 @@ class EventManagerIF {
|
||||
|
||||
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
|
||||
bool forwardAllButSelected = false) = 0;
|
||||
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
|
||||
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
||||
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
|
@ -24,7 +24,7 @@ FailureIsolationBase::~FailureIsolationBase() {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
||||
manager->unregisterListener(eventQueue->getId());
|
||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
parameterWrapper->set(faultCount);
|
||||
break;
|
||||
case ParameterIds::TIMEOUT:
|
||||
parameterWrapper->set(timer.timeout);
|
||||
parameterWrapper->set(timer.getTimeoutMs());
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
|
@ -74,6 +74,12 @@ class HasFileSystemIF {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
|
||||
// Get the base filename without the full directory path
|
||||
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen,
|
||||
size_t& baseNameLen) = 0;
|
||||
|
||||
virtual bool isDirectory(const char* path) = 0;
|
||||
|
||||
virtual bool fileExists(FilesystemParams params) = 0;
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
MatchTree(iterator root, uint8_t maxDepth = -1)
|
||||
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
||||
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
||||
virtual ~MatchTree() {}
|
||||
virtual ~MatchTree() { clear(); }
|
||||
virtual bool match(T number) override { return matchesTree(number); }
|
||||
bool matchesTree(T number) {
|
||||
iterator iter = this->begin();
|
||||
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
|
||||
|
||||
if (localRoot == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* node = localRoot->left;
|
||||
|
||||
while (true) {
|
||||
if (node->left != nullptr) {
|
||||
node = node->left;
|
||||
continue;
|
||||
}
|
||||
if (node->right != nullptr) {
|
||||
node = node->right;
|
||||
continue;
|
||||
}
|
||||
if (node->parent == nullptr) {
|
||||
// this is the root node with no children
|
||||
if (node->value != nullptr) {
|
||||
cleanUpElement(iterator(node));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// leaf
|
||||
{
|
||||
Node* parent = node->parent;
|
||||
if (parent->left == node) {
|
||||
parent->left = nullptr;
|
||||
} else {
|
||||
parent->right = nullptr;
|
||||
}
|
||||
cleanUpElement(iterator(node));
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
|
||||
|
||||
bool matchSubtree(iterator iter, T number) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "fsfw/globalfunctions/timevalOperations.h"
|
||||
|
||||
timeval& operator+=(timeval& lhs, const timeval& rhs) {
|
||||
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
|
||||
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
|
||||
int64_t sum = static_cast<int64_t>(lhs.tv_sec) * 1000000. + lhs.tv_usec;
|
||||
sum += static_cast<int64_t>(rhs.tv_sec) * 1000000. + rhs.tv_usec;
|
||||
lhs.tv_sec = sum / 1000000;
|
||||
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
|
||||
return lhs;
|
||||
|
@ -5,7 +5,11 @@
|
||||
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
|
||||
: objectId(objectId), owner(owner) {}
|
||||
|
||||
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
|
||||
HealthHelper::~HealthHelper() {
|
||||
if (healthTable != nullptr) {
|
||||
healthTable->removeObject(objectId);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
|
||||
switch (message->getCommand()) {
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
;
|
||||
|
||||
mapIterator = healthMap.begin();
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include "HealthTableIF.h"
|
||||
|
||||
class HealthTable : public HealthTableIF, public SystemObject {
|
||||
friend class CServiceHealthCommanding;
|
||||
|
||||
public:
|
||||
explicit HealthTable(object_id_t objectid);
|
||||
~HealthTable() override;
|
||||
|
@ -10,13 +10,17 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t m
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
InternalErrorReporter::~InternalErrorReporter() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
this->diagnosticPrintout = enable;
|
||||
|
@ -7,14 +7,17 @@
|
||||
class MutexGuard {
|
||||
public:
|
||||
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
|
||||
uint32_t timeoutMs = 0)
|
||||
uint32_t timeoutMs = 0, const char* context = nullptr)
|
||||
: internalMutex(mutex) {
|
||||
if (context == nullptr) {
|
||||
context = "unknown";
|
||||
}
|
||||
if (mutex == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl;
|
||||
sif::error << "MutexGuard::" << context << ": Passed mutex is invalid!" << std::endl;
|
||||
#else
|
||||
sif::printError("MutexGuard: Passed mutex is invalid!\n");
|
||||
sif::printError("MutexGuard::%s: Passed mutex is invalid!\n", context);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return;
|
||||
@ -23,11 +26,11 @@ class MutexGuard {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
if (result == MutexIF::MUTEX_TIMEOUT) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs
|
||||
<< " milliseconds!" << std::endl;
|
||||
sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of "
|
||||
<< timeoutMs << " milliseconds!" << std::endl;
|
||||
#else
|
||||
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
|
||||
timeoutMs);
|
||||
sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n",
|
||||
context, timeoutMs);
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
|
||||
} else if (result != returnvalue::OK) {
|
||||
|
@ -24,3 +24,19 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason
|
||||
message->setParameter(reason);
|
||||
message->setParameter2(0);
|
||||
}
|
||||
|
||||
void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) {
|
||||
Command_t cmd;
|
||||
if (recursive) {
|
||||
cmd = CMD_MODE_ANNOUNCE_RECURSIVELY;
|
||||
} else {
|
||||
cmd = CMD_MODE_ANNOUNCE;
|
||||
}
|
||||
message.setCommand(cmd);
|
||||
}
|
||||
|
||||
void ModeMessage::setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) {
|
||||
setModeMessage(&message, CMD_MODE_COMMAND, mode, submode);
|
||||
}
|
||||
|
||||
void ModeMessage::setModeReadMessage(CommandMessage& message) { message.setCommand(CMD_MODE_READ); }
|
||||
|
@ -1,43 +1,42 @@
|
||||
#ifndef FSFW_MODES_MODEMESSAGE_H_
|
||||
#define FSFW_MODES_MODEMESSAGE_H_
|
||||
|
||||
#include "../ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
|
||||
typedef uint32_t Mode_t;
|
||||
typedef uint8_t Submode_t;
|
||||
|
||||
class ModeMessage {
|
||||
private:
|
||||
ModeMessage();
|
||||
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
||||
static const Command_t CMD_MODE_COMMAND =
|
||||
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||
//! as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
|
||||
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
|
||||
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||
//! replies, as this will break the subsystem mode machine!!
|
||||
static const Command_t REPLY_MODE_REPLY =
|
||||
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||
static const Command_t REPLY_MODE_INFO =
|
||||
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
|
||||
//! inform their container of a changed mode)
|
||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
|
||||
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||
static const Command_t REPLY_WRONG_MODE_REPLY =
|
||||
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||
//! and a transition started but was aborted; the parameters contain
|
||||
//! the mode that was reached
|
||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
|
||||
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
|
||||
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
|
||||
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
|
||||
//! every child. This command does NOT have a reply.
|
||||
//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||
//! as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);
|
||||
//!> Command to set the specified Mode, regardless of external control flag, replies
|
||||
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||
//! replies, as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);
|
||||
//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||
static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);
|
||||
//!> Unrequested info about the current mode (used for composites to
|
||||
//! inform their container of a changed mode)
|
||||
static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03);
|
||||
//!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04);
|
||||
//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||
//! and a transition started but was aborted; the parameters contain
|
||||
//! the mode that was reached
|
||||
static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);
|
||||
//!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);
|
||||
//!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);
|
||||
//!> Command to trigger an ModeInfo Event and to send this command to
|
||||
//! every child. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = MAKE_COMMAND_ID(0x08);
|
||||
|
||||
ModeMessage() = delete;
|
||||
|
||||
static Mode_t getMode(const CommandMessage* message);
|
||||
static Submode_t getSubmode(const CommandMessage* message);
|
||||
@ -45,6 +44,9 @@ class ModeMessage {
|
||||
|
||||
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
|
||||
Submode_t submode);
|
||||
static void setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode);
|
||||
static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
|
||||
static void setModeReadMessage(CommandMessage& message);
|
||||
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
|
||||
static void clear(CommandMessage* message);
|
||||
};
|
||||
|
@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
|
||||
|
||||
ObjectManager::ObjectManager() = default;
|
||||
|
||||
void ObjectManager::clear() {
|
||||
if (objManagerInstance != nullptr) {
|
||||
delete objManagerInstance;
|
||||
objManagerInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectManager::~ObjectManager() {
|
||||
for (auto const& iter : objectList) {
|
||||
delete iter.second;
|
||||
teardown = true;
|
||||
for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
|
||||
}
|
||||
|
||||
ReturnValue_t ObjectManager::remove(object_id_t id) {
|
||||
// this function is called during destruction of System Objects
|
||||
// disabeld for teardown to avoid iterator invalidation and
|
||||
// double free
|
||||
if (teardown) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
if (this->getSystemObject(id) != nullptr) {
|
||||
this->objectList.erase(id);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF {
|
||||
using produce_function_t = void (*)(void* args);
|
||||
|
||||
/**
|
||||
* Returns the single instance of TaskFactory.
|
||||
* Returns the single instance of ObjectManager.
|
||||
* The implementation of #instance is found in its subclasses.
|
||||
* Thus, we choose link-time variability of the instance.
|
||||
*/
|
||||
static ObjectManager* instance();
|
||||
|
||||
/**
|
||||
* Deletes the single instance of ObjectManager
|
||||
*/
|
||||
static void clear();
|
||||
|
||||
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
|
||||
|
||||
template <typename T>
|
||||
@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF {
|
||||
*/
|
||||
std::map<object_id_t, SystemObjectIF*> objectList;
|
||||
static ObjectManager* objManagerInstance;
|
||||
// used when the OM itself is deleted to modify behaviour of remove()
|
||||
// to avoid iterator invalidation and double free
|
||||
bool teardown = false;
|
||||
};
|
||||
|
||||
// Documentation can be found in the class method declaration above
|
||||
|
@ -15,6 +15,7 @@ enum framework_objects : object_id_t {
|
||||
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
||||
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
||||
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
|
||||
PUS_SERVICE_15_TM_STORAGE = 0x53000015,
|
||||
PUS_SERVICE_17_TEST = 0x53000017,
|
||||
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
||||
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
||||
|
@ -1,10 +1,13 @@
|
||||
# Check the OS_FSFW variable
|
||||
if(FSFW_OSAL MATCHES "freertos")
|
||||
add_subdirectory(freertos)
|
||||
set(FSFW_OSAL_FREERTOS 1)
|
||||
elseif(FSFW_OSAL MATCHES "rtems")
|
||||
add_subdirectory(rtems)
|
||||
set(FSFW_OSAL_RTEMS 1)
|
||||
elseif(FSFW_OSAL MATCHES "linux")
|
||||
add_subdirectory(linux)
|
||||
set(FSFW_OSAL_LINUX 1)
|
||||
elseif(FSFW_OSAL MATCHES "host")
|
||||
add_subdirectory(host)
|
||||
if(WIN32)
|
||||
@ -13,18 +16,20 @@ elseif(FSFW_OSAL MATCHES "host")
|
||||
# We still need to pull in some Linux specific sources
|
||||
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
|
||||
endif()
|
||||
|
||||
set(FSFW_OSAL_HOST 1)
|
||||
else()
|
||||
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
||||
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if(WIN32)
|
||||
add_subdirectory(host)
|
||||
add_subdirectory(windows)
|
||||
set(FSFW_OSAL_HOST 1)
|
||||
elseif(UNIX)
|
||||
add_subdirectory(linux)
|
||||
set(FSFW_OSAL_LINUX 1)
|
||||
else()
|
||||
# MacOS or other OSes have not been tested yet / are not supported.
|
||||
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
||||
@ -33,3 +38,5 @@ else()
|
||||
endif()
|
||||
|
||||
add_subdirectory(common)
|
||||
|
||||
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)
|
||||
|
@ -41,6 +41,7 @@ int TcpIpBase::closeSocket(socket_t socket) {
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
return close(socket);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int TcpIpBase::getLastSocketError() {
|
||||
@ -49,4 +50,5 @@ int TcpIpBase::getLastSocketError() {
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
return errno;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
#endif
|
||||
|
||||
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
|
||||
object_id_t tcStoreId)
|
||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
|
||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
// Connection is always up, TM is requested by connecting to server and receiving packets
|
||||
registerCommConnect();
|
||||
|
@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge {
|
||||
* @param tmStoreId TM store object ID. It is recommended to the default object ID
|
||||
* @param tcStoreId TC store object ID. It is recommended to the default object ID
|
||||
*/
|
||||
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth,
|
||||
object_id_t tmStoreId = objects::TM_STORE,
|
||||
object_id_t tcStoreId = objects::TC_STORE);
|
||||
virtual ~TcpTmTcBridge();
|
||||
|
@ -26,12 +26,12 @@
|
||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||
|
||||
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
size_t receptionBufferSize, size_t ringBufferSize,
|
||||
std::string customTcpServerPort, ReceptionModes receptionMode)
|
||||
TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize,
|
||||
size_t ringBufferSize, ReceptionModes receptionMode)
|
||||
: SystemObject(objectId),
|
||||
tmtcBridgeId(tmtcTcpBridge),
|
||||
receptionMode(receptionMode),
|
||||
tcpConfig(std::move(customTcpServerPort)),
|
||||
tcpConfig(cfg),
|
||||
receptionBuffer(receptionBufferSize),
|
||||
ringBuffer(ringBufferSize, true) {}
|
||||
|
||||
@ -91,6 +91,15 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (tcpConfig.reuseAddr) {
|
||||
unsigned int enable = 1;
|
||||
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
}
|
||||
if (tcpConfig.reusePort) {
|
||||
unsigned int enable = 1;
|
||||
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
|
||||
}
|
||||
|
||||
// Bind to the address found by getaddrinfo
|
||||
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||
if (retval == SOCKET_ERROR) {
|
||||
@ -274,6 +283,8 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
||||
ConstStorageAccessor storeAccessor(storeId);
|
||||
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
|
||||
if (result != returnvalue::OK) {
|
||||
// Invalid entry, pop FIFO
|
||||
tmtcBridge->tmFifo->pop();
|
||||
return result;
|
||||
}
|
||||
if (wiretappingEnabled) {
|
||||
|
@ -41,11 +41,11 @@ class SpacePacketParser;
|
||||
*/
|
||||
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
|
||||
public:
|
||||
enum class ReceptionModes { SPACE_PACKETS };
|
||||
|
||||
struct TcpConfig {
|
||||
public:
|
||||
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
||||
TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||
TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort)
|
||||
: tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||
|
||||
/**
|
||||
* Passed to the recv call
|
||||
@ -63,9 +63,25 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
*/
|
||||
int tcpTmFlags = 0;
|
||||
|
||||
const std::string tcpPort;
|
||||
std::string tcpPort = DEFAULT_SERVER_PORT;
|
||||
|
||||
/**
|
||||
* Sets the SO_REUSEADDR option on the socket. See
|
||||
* https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is
|
||||
* especially useful in a debugging and development environment where an OBSW image might be
|
||||
* re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP
|
||||
* port.
|
||||
*/
|
||||
bool reuseAddr = false;
|
||||
/**
|
||||
* Sets the SO_REUSEPORT option on the socket. See
|
||||
* https://man7.org/linux/man-pages/man7/socket.7.html for more details.
|
||||
*/
|
||||
bool reusePort = false;
|
||||
};
|
||||
|
||||
enum class ReceptionModes { SPACE_PACKETS };
|
||||
|
||||
static const std::string DEFAULT_SERVER_PORT;
|
||||
|
||||
static constexpr size_t ETHERNET_MTU_SIZE = 1500;
|
||||
@ -80,10 +96,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
* size will be the Ethernet MTU size
|
||||
* @param customTcpServerPort The user can specify another port than the default (7301) here.
|
||||
*/
|
||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg,
|
||||
size_t receptionBufferSize = RING_BUFFER_SIZE,
|
||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||
~TcpTmTcServer() override;
|
||||
|
||||
|
@ -20,9 +20,9 @@
|
||||
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||
|
||||
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
const std::string &udpServerPort_, object_id_t tmStoreId,
|
||||
object_id_t tcStoreId)
|
||||
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||
uint32_t msgQueueDepth, const std::string &udpServerPort_,
|
||||
object_id_t tmStoreId, object_id_t tcStoreId)
|
||||
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||
if (udpServerPort_.empty()) {
|
||||
udpServerPort = DEFAULT_SERVER_PORT;
|
||||
} else {
|
||||
@ -126,10 +126,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent
|
||||
<< " bytes were"
|
||||
" sent."
|
||||
<< std::endl;
|
||||
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were sent" << std::endl;
|
||||
#endif
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase {
|
||||
/* The ports chosen here should not be used by any other process. */
|
||||
static const std::string DEFAULT_SERVER_PORT;
|
||||
|
||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth,
|
||||
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||
object_id_t tcStoreId = objects::TC_STORE);
|
||||
~UdpTmTcBridge() override;
|
||||
|
@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
ReturnValue_t Clock::getClockMonotonic(timeval* time) {
|
||||
#if defined(PLATFORM_WIN)
|
||||
// TODO: Implement with std::chrono::steady_clock.. or in some other way. I am not even sure
|
||||
// whether this is possible with steady_clock. The conversion we have to do here just to be
|
||||
// generic is kind of awkward..
|
||||
return returnvalue::FAILED;
|
||||
#elif defined(PLATFORM_UNIX)
|
||||
timespec timeMonotonic;
|
||||
int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic);
|
||||
if (status != 0) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
time->tv_sec = timeMonotonic.tv_sec;
|
||||
time->tv_usec = timeMonotonic.tv_nsec / 1000.0;
|
||||
return returnvalue::OK;
|
||||
#else
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
|
||||
#else
|
||||
sif::printWarning("Clock::getUptime: Not implemented for found OS!\n");
|
||||
#endif
|
||||
return returnvalue::FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock(timeval* time) {
|
||||
#if defined(PLATFORM_WIN)
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
|
||||
@ -75,6 +100,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
#endif
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
|
||||
|
||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||
if (time == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
|
@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
ReturnValue_t Clock::getClock(timeval* time) {
|
||||
timespec timeUnix{};
|
||||
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
|
||||
if (status != 0) {
|
||||
@ -53,6 +53,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); }
|
||||
|
||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||
timeval timeVal{};
|
||||
ReturnValue_t result = getClock_timeval(&timeVal);
|
||||
@ -64,6 +66,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClockMonotonic(timeval* time) {
|
||||
timespec timeMonotonic{};
|
||||
int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic);
|
||||
if (status != 0) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
time->tv_sec = timeMonotonic.tv_sec;
|
||||
time->tv_usec = timeMonotonic.tv_nsec / 1000.0;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
timeval Clock::getUptime() {
|
||||
timeval uptime{};
|
||||
auto result = getUptime(&uptime);
|
||||
@ -79,11 +92,16 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
||||
// TODO This is not posix compatible and delivers only seconds precision
|
||||
// Linux specific file read but more precise.
|
||||
double uptimeSeconds;
|
||||
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
|
||||
std::ifstream ifile("/proc/uptime");
|
||||
if (ifile.bad()) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
if (ifile >> uptimeSeconds) {
|
||||
uptime->tv_sec = uptimeSeconds;
|
||||
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
// Wait for new FSFW Clock function delivering seconds uptime.
|
||||
|
@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs*
|
||||
attributes.mq_msgsize = maxMessageSize;
|
||||
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
|
||||
// Set the name of the queue. The slash is mandatory!
|
||||
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
|
||||
sprintf(name, "/FSFW_MQ%u", queueCounter++);
|
||||
|
||||
// Create a nonblocking queue if the name is available (the queue is read
|
||||
// and writable for the owner as well as the group)
|
||||
|
36
src/fsfw/osal/osal.h.in
Normal file
36
src/fsfw/osal/osal.h.in
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
namespace osal {
|
||||
enum osalTarget{
|
||||
HOST,
|
||||
LINUX,
|
||||
WINDOWS,
|
||||
FREERTOS,
|
||||
RTEMS,
|
||||
};
|
||||
|
||||
#cmakedefine FSFW_OSAL_HOST
|
||||
#cmakedefine FSFW_OSAL_LINUX
|
||||
#cmakedefine FSFW_OSAL_WINDOWS
|
||||
#cmakedefine FSFW_OSAL_FREERTOS
|
||||
#cmakedefine FSFW_OSAL_RTEMS
|
||||
|
||||
|
||||
constexpr osalTarget getTarget() {
|
||||
#ifdef FSFW_OSAL_HOST
|
||||
return HOST;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_LINUX
|
||||
return LINUX;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_WINDOWS
|
||||
return WINDOWS;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_FREERTOS
|
||||
return FREERTOS;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_RTEMS
|
||||
return RTEMS;
|
||||
#endif
|
||||
}
|
||||
};
|
@ -1,5 +1,7 @@
|
||||
#include "DummyPowerSwitcher.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches,
|
||||
size_t numberOfFuses, bool registerGlobally,
|
||||
uint32_t switchDelayMs)
|
||||
@ -9,11 +11,11 @@ DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwit
|
||||
switchDelayMs(switchDelayMs) {}
|
||||
|
||||
void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) {
|
||||
this->switcherList = switcherList;
|
||||
this->switcherList = std::move(switcherList);
|
||||
}
|
||||
|
||||
void DummyPowerSwitcher::setInitialFusesList(std::vector<ReturnValue_t> fuseList) {
|
||||
this->fuseList = fuseList;
|
||||
this->fuseList = std::move(fuseList);
|
||||
}
|
||||
|
||||
ReturnValue_t DummyPowerSwitcher::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/power/PowerSwitchIF.h>
|
||||
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||
power::Switch_t pwrSwitch)
|
||||
: SystemObject(objectId),
|
||||
switcher(pwrSwitcher, pwrSwitch),
|
||||
@ -54,7 +54,7 @@ ReturnValue_t PowerSwitcherComponent::initialize() {
|
||||
|
||||
MessageQueueId_t PowerSwitcherComponent::getCommandQueue() const { return queue->getId(); }
|
||||
|
||||
void PowerSwitcherComponent::getMode(Mode_t *mode, Submode_t *submode) {
|
||||
void PowerSwitcherComponent::getMode(Mode_t* mode, Submode_t* submode) {
|
||||
*mode = this->mode;
|
||||
*submode = this->submode;
|
||||
}
|
||||
@ -65,7 +65,7 @@ ReturnValue_t PowerSwitcherComponent::setHealth(HealthState health) {
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) {
|
||||
uint32_t* msToReachTheMode) {
|
||||
*msToReachTheMode = 5000;
|
||||
if (mode != MODE_ON and mode != MODE_OFF) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
@ -105,3 +105,15 @@ void PowerSwitcherComponent::setMode(Mode_t newMode, Submode_t newSubmode) {
|
||||
}
|
||||
|
||||
HasHealthIF::HealthState PowerSwitcherComponent::getHealth() { return healthHelper.getHealth(); }
|
||||
|
||||
const HasHealthIF* PowerSwitcherComponent::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return parent.registerChild(*this);
|
||||
}
|
||||
|
||||
object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/power/PowerSwitcher.h>
|
||||
#include <fsfw/power/definitions.h>
|
||||
#include <fsfw/subsystem/ModeTreeChildIF.h>
|
||||
#include <fsfw/subsystem/ModeTreeConnectionIF.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
|
||||
class PowerSwitchIF;
|
||||
@ -24,12 +26,17 @@ class PowerSwitchIF;
|
||||
*/
|
||||
class PowerSwitcherComponent : public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF {
|
||||
public:
|
||||
PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
|
||||
power::Switch_t pwrSwitch);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
private:
|
||||
MessageQueueIF *queue = nullptr;
|
||||
PowerSwitcher switcher;
|
||||
@ -56,6 +63,10 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
object_id_t getObjectId() const override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
};
|
||||
|
||||
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */
|
||||
|
@ -9,4 +9,4 @@ target_sources(
|
||||
Service17Test.cpp
|
||||
Service20ParameterManagement.cpp
|
||||
CService200ModeCommanding.cpp
|
||||
CService201HealthCommanding.cpp)
|
||||
CServiceHealthCommanding.cpp)
|
||||
|
@ -19,7 +19,8 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_MODE_COMMAND):
|
||||
case (Subservice::COMMAND_MODE_READ):
|
||||
case (Subservice::COMMAND_MODE_ANNCOUNCE):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
@ -53,16 +54,32 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||
const uint8_t *tcData, size_t tcDataLen,
|
||||
uint32_t *state, object_id_t objectId) {
|
||||
ModePacket modeCommandPacket;
|
||||
ReturnValue_t result =
|
||||
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
bool recursive = false;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_MODE_COMMAND): {
|
||||
ModePacket modeCommandPacket;
|
||||
ReturnValue_t result =
|
||||
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
||||
modeCommandPacket.getSubmode());
|
||||
return result;
|
||||
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND,
|
||||
modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||
recursive = true;
|
||||
[[fallthrough]];
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE):
|
||||
ModeMessage::setModeAnnounceMessage(*message, recursive);
|
||||
return EXECUTION_COMPLETE;
|
||||
case (Subservice::COMMAND_MODE_READ):
|
||||
ModeMessage::setModeReadMessage(*message);
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return CommandingServiceBase::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply,
|
||||
@ -73,8 +90,10 @@ ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
switch (replyId) {
|
||||
case (ModeMessage::REPLY_MODE_REPLY): {
|
||||
result = prepareModeReply(reply, objectId);
|
||||
break;
|
||||
if (previousCommand != ModeMessage::CMD_MODE_COMMAND) {
|
||||
return prepareModeReply(reply, objectId);
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (ModeMessage::REPLY_WRONG_MODE_REPLY): {
|
||||
result = prepareWrongModeReply(reply, objectId);
|
||||
|
@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase {
|
||||
COMMAND_MODE_READ = 3,
|
||||
//!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event.
|
||||
//! This command does NOT have a reply
|
||||
COMMAND_MODE_ANNCOUNCE = 4,
|
||||
COMMAND_MODE_ANNOUNCE = 4,
|
||||
//!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this
|
||||
//! command to every child. This command does NOT have a reply.
|
||||
COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5,
|
||||
|
@ -1,106 +0,0 @@
|
||||
#include "fsfw/pus/CService201HealthCommanding.h"
|
||||
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthMessage.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid,
|
||||
uint8_t serviceId,
|
||||
uint8_t numParallelCommands,
|
||||
uint16_t commandTimeoutSeconds)
|
||||
: CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands,
|
||||
commandTimeoutSeconds) {}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Invalid Subservice" << std::endl;
|
||||
#endif
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
||||
const uint8_t *tcData,
|
||||
size_t tcDataLen,
|
||||
MessageQueueId_t *id,
|
||||
object_id_t *objectId) {
|
||||
if (tcDataLen < sizeof(object_id_t)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
|
||||
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||
if (destination == nullptr) {
|
||||
return CommandingServiceBase::INVALID_OBJECT;
|
||||
}
|
||||
|
||||
*messageQueueToSet = destination->getCommandQueue();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message,
|
||||
uint8_t subservice, const uint8_t *tcData,
|
||||
size_t tcDataLen, uint32_t *state,
|
||||
object_id_t objectId) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH): {
|
||||
HealthSetCommand healthCommand;
|
||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
break;
|
||||
}
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
||||
healthCommand.getHealth());
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Should never happen, subservice was already checked
|
||||
result = returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply,
|
||||
Command_t previousCommand, uint32_t *state,
|
||||
CommandMessage *optionalNextCommand,
|
||||
object_id_t objectId, bool *isStep) {
|
||||
Command_t replyId = reply->getCommand();
|
||||
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
||||
return EXECUTION_COMPLETE;
|
||||
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
||||
return reply->getReplyRejectedReason();
|
||||
}
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
}
|
||||
|
||||
// Not used for now, health state already reported by event
|
||||
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
|
||||
const CommandMessage *reply) {
|
||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||
HealthSetReply healthSetReply(health, oldHealth);
|
||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
||||
}
|
155
src/fsfw/pus/CServiceHealthCommanding.cpp
Normal file
155
src/fsfw/pus/CServiceHealthCommanding.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
#include <fsfw/events/EventManagerIF.h>
|
||||
#include <fsfw/pus/CServiceHealthCommanding.h>
|
||||
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthMessage.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
||||
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
||||
args.numParallelCommands, args.commandTimeoutSeconds),
|
||||
healthTable(args.table),
|
||||
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Invalid Subservice" << std::endl;
|
||||
#endif
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
||||
const uint8_t *tcData,
|
||||
size_t tcDataLen,
|
||||
MessageQueueId_t *id,
|
||||
object_id_t *objectId) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
if (tcDataLen < sizeof(object_id_t)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
|
||||
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default: {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||
if (destination == nullptr) {
|
||||
return CommandingServiceBase::INVALID_OBJECT;
|
||||
}
|
||||
|
||||
*messageQueueToSet = destination->getCommandQueue();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||
const uint8_t *tcData, size_t tcDataLen,
|
||||
uint32_t *state, object_id_t objectId) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH): {
|
||||
if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) {
|
||||
return CommandingServiceBase::INVALID_TC;
|
||||
}
|
||||
HealthSetCommand healthCommand;
|
||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
break;
|
||||
}
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
||||
healthCommand.getHealth());
|
||||
break;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
ReturnValue_t result = iterateHealthTable(true);
|
||||
if (result == returnvalue::OK) {
|
||||
reportAllHealth = true;
|
||||
return EXECUTION_COMPLETE;
|
||||
}
|
||||
return result;
|
||||
while (true) {
|
||||
ReturnValue_t result = iterateHealthTable(false);
|
||||
if (result != returnvalue::OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default: {
|
||||
// Should never happen, subservice was already checked
|
||||
result = returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply,
|
||||
Command_t previousCommand, uint32_t *state,
|
||||
CommandMessage *optionalNextCommand,
|
||||
object_id_t objectId, bool *isStep) {
|
||||
Command_t replyId = reply->getCommand();
|
||||
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
||||
return EXECUTION_COMPLETE;
|
||||
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
||||
return reply->getReplyRejectedReason();
|
||||
}
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
}
|
||||
|
||||
void CServiceHealthCommanding::doPeriodicOperation() {
|
||||
if (reportAllHealth) {
|
||||
for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) {
|
||||
ReturnValue_t result = iterateHealthTable(false);
|
||||
if (result != returnvalue::OK) {
|
||||
reportAllHealth = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not used for now, health state already reported by event
|
||||
[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply(
|
||||
const CommandMessage *reply) {
|
||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||
HealthSetReply healthSetReply(health, oldHealth);
|
||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
||||
std::pair<object_id_t, HasHealthIF::HealthState> pair;
|
||||
|
||||
ReturnValue_t result = healthTable.iterate(&pair, reset);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
} else {
|
||||
EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
@ -1,8 +1,26 @@
|
||||
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
|
||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||
|
||||
struct HealthServiceCfg {
|
||||
HealthServiceCfg(object_id_t objectId, uint16_t apid, HealthTable &healthTable,
|
||||
uint16_t maxNumHealthInfoPerCycle)
|
||||
: objectId(objectId),
|
||||
apid(apid),
|
||||
table(healthTable),
|
||||
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
||||
object_id_t objectId;
|
||||
uint16_t apid;
|
||||
HealthTable &table;
|
||||
uint16_t maxNumHealthInfoPerCycle;
|
||||
uint8_t service = 201;
|
||||
uint8_t numParallelCommands = 4;
|
||||
uint16_t commandTimeoutSeconds = 60;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom PUS service to set health of all objects
|
||||
* implementing hasHealthIF.
|
||||
@ -17,11 +35,10 @@
|
||||
* child class like this service
|
||||
*
|
||||
*/
|
||||
class CService201HealthCommanding : public CommandingServiceBase {
|
||||
class CServiceHealthCommanding : public CommandingServiceBase {
|
||||
public:
|
||||
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
||||
~CService201HealthCommanding() override = default;
|
||||
CServiceHealthCommanding(HealthServiceCfg args);
|
||||
~CServiceHealthCommanding() override = default;
|
||||
|
||||
protected:
|
||||
/* CSB abstract function implementations */
|
||||
@ -37,7 +54,13 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
||||
CommandMessage *optionalNextCommand, object_id_t objectId,
|
||||
bool *isStep) override;
|
||||
|
||||
void doPeriodicOperation() override;
|
||||
|
||||
private:
|
||||
HealthTable &healthTable;
|
||||
uint16_t maxNumHealthInfoPerCycle = 0;
|
||||
bool reportAllHealth = false;
|
||||
ReturnValue_t iterateHealthTable(bool reset);
|
||||
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
||||
const object_id_t *objectId);
|
||||
|
@ -41,6 +41,8 @@ class Service11TelecommandScheduling final : public PusServiceBase {
|
||||
static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2);
|
||||
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3);
|
||||
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
|
||||
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
|
||||
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;
|
||||
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
|
||||
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
||||
@ -158,7 +160,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
|
||||
// (See requirement for Time margin)
|
||||
timeval tNow = {};
|
||||
Clock::getClock_timeval(&tNow);
|
||||
if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) {
|
||||
if (timestamp < static_cast<uint32_t>(tNow.tv_sec + RELEASE_TIME_MARGIN_SECONDS)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to "
|
||||
"current time"
|
||||
@ -171,6 +173,14 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (size < PusTcIF::MIN_SIZE) {
|
||||
return CONTAINED_TC_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (CRC::crc16ccitt(data, size) != 0) {
|
||||
return CONTAINED_TC_CRC_MISSMATCH;
|
||||
}
|
||||
|
||||
// store currentPacket and receive the store address
|
||||
store_address_t addr{};
|
||||
if (tcStore->addData(&addr, data, size) != returnvalue::OK ||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "fsfw/pus/Service17Test.h"
|
||||
|
||||
#include <fsfw/serialize/SerializeElement.h>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
@ -31,6 +33,15 @@ ReturnValue_t Service17Test::handleRequest(uint8_t subservice) {
|
||||
}
|
||||
return tmHelper.storeAndSendTmPacket();
|
||||
}
|
||||
case Subservice::PING_WITH_DATA: {
|
||||
SerializeElement<uint32_t> receivedDataLen = currentPacket.getUserDataLen();
|
||||
ReturnValue_t result =
|
||||
tmHelper.prepareTmPacket(Subservice::PING_WITH_DATA_REPORT_WITH_SIZE, receivedDataLen);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return tmHelper.storeAndSendTmPacket();
|
||||
}
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ class Service17Test : public PusServiceBase {
|
||||
CONNECTION_TEST_REPORT = 2,
|
||||
//! [EXPORT] : [COMMAND] Trigger test reply and test event
|
||||
EVENT_TRIGGER_TEST = 128,
|
||||
PING_WITH_DATA = 129,
|
||||
//! [EXPORT] : [COMMAND] Report which reports the sent user data size
|
||||
PING_WITH_DATA_REPORT_WITH_SIZE = 130
|
||||
};
|
||||
|
||||
explicit Service17Test(PsbParams params);
|
||||
|
@ -69,14 +69,14 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
|
||||
<< "MessageQueue: Can't access object" << std::endl;
|
||||
sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl;
|
||||
sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl;
|
||||
sif::error << "Object ID: 0x" << std::hex << *objectId << std::dec << std::endl;
|
||||
sif::error << "Make sure it implements ReceivesParameterMessagesIF" << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"Service20ParameterManagement::checkInterfaceAndAcquire"
|
||||
"MessageQueue: Can't access object\n");
|
||||
sif::printError("Object ID: 0x%08x\n", *objectId);
|
||||
sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n");
|
||||
sif::printError("Make sure it implements ReceivesParameterMessagesIF\n");
|
||||
#endif
|
||||
|
||||
return CommandingServiceBase::INVALID_OBJECT;
|
||||
|
@ -42,7 +42,7 @@
|
||||
class Service5EventReporting : public PusServiceBase {
|
||||
public:
|
||||
Service5EventReporting(PsbParams params, size_t maxNumberReportsPerCycle = 10,
|
||||
uint32_t messageQueueDepth = 10);
|
||||
uint32_t messageQueueDepth = 20);
|
||||
~Service5EventReporting() override;
|
||||
|
||||
/***
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "fsfw/pus/Service9TimeManagement.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "fsfw/events/EventManagerIF.h"
|
||||
#include "fsfw/pus/servicepackets/Service9Packets.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
@ -15,9 +17,17 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK;
|
||||
|
||||
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case SUBSERVICE::SET_TIME: {
|
||||
case Subservice::SET_TIME: {
|
||||
return setTime();
|
||||
}
|
||||
case Subservice::DUMP_TIME: {
|
||||
timeval newTime;
|
||||
Clock::getClock_timeval(&newTime);
|
||||
uint32_t subsecondMs =
|
||||
static_cast<uint32_t>(std::floor(static_cast<double>(newTime.tv_usec) / 1000.0));
|
||||
triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
@ -33,14 +43,14 @@ ReturnValue_t Service9TimeManagement::setTime() {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t formerUptime;
|
||||
Clock::getUptime(&formerUptime);
|
||||
timeval time;
|
||||
Clock::getClock_timeval(&time);
|
||||
result = Clock::setClock(&timeToSet);
|
||||
|
||||
if (result == returnvalue::OK) {
|
||||
uint32_t newUptime;
|
||||
Clock::getUptime(&newUptime);
|
||||
triggerEvent(CLOCK_SET, newUptime, formerUptime);
|
||||
timeval newTime;
|
||||
Clock::getClock_timeval(&newTime);
|
||||
triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec);
|
||||
return returnvalue::OK;
|
||||
} else {
|
||||
triggerEvent(CLOCK_SET_FAILURE, result, 0);
|
||||
|
@ -6,10 +6,13 @@
|
||||
class Service9TimeManagement : public PusServiceBase {
|
||||
public:
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
||||
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
|
||||
//!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds.
|
||||
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||
//!< Clock dump event. P1: timeval seconds P2: timeval milliseconds.
|
||||
static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO);
|
||||
//!< Clock could not be set. P1: Returncode.
|
||||
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
|
||||
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW);
|
||||
|
||||
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
||||
|
||||
@ -30,8 +33,9 @@ class Service9TimeManagement : public PusServiceBase {
|
||||
virtual ReturnValue_t setTime();
|
||||
|
||||
private:
|
||||
enum SUBSERVICE {
|
||||
SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
|
||||
enum Subservice {
|
||||
SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
|
||||
DUMP_TIME = 129,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_
|
||||
#define FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_
|
||||
|
||||
#include "../../modes/ModeMessage.h"
|
||||
#include "../../serialize/SerialLinkedListAdapter.h"
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
#include "fsfw/modes/ModeMessage.h"
|
||||
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief Subservice 1, 2, 3, 4, 5
|
||||
|
@ -31,9 +31,8 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
|
||||
|
||||
LocalPool::~LocalPool() = default;
|
||||
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId);
|
||||
if (status == returnvalue::OK) {
|
||||
write(*storageId, data, size);
|
||||
}
|
||||
@ -49,8 +48,8 @@ ReturnValue_t LocalPool::getData(store_address_t packetId, const uint8_t** packe
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getFreeElement(store_address_t* storageId, const size_t size,
|
||||
uint8_t** pData, bool ignoreFault) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
|
||||
uint8_t** pData) {
|
||||
ReturnValue_t status = reserveSpace(size, storageId);
|
||||
if (status == returnvalue::OK) {
|
||||
*pData = &store[storageId->poolIndex][getRawPosition(*storageId)];
|
||||
} else {
|
||||
@ -167,7 +166,7 @@ void LocalPool::clearStore() {
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId, bool ignoreFault) {
|
||||
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId) {
|
||||
ReturnValue_t status = getSubPoolIndex(size, &storeId->poolIndex);
|
||||
if (status != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -318,27 +317,3 @@ bool LocalPool::hasDataAtId(store_address_t storeId) const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) {
|
||||
return StorageManagerIF::getFreeElement(storeId, size, pData);
|
||||
}
|
||||
|
||||
ConstAccessorPair LocalPool::getData(store_address_t storeId) {
|
||||
return StorageManagerIF::getData(storeId);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::addData(store_address_t* storeId, const uint8_t* data, size_t size) {
|
||||
return StorageManagerIF::addData(storeId, data, size);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::getData(store_address_t storeId, ConstStorageAccessor& accessor) {
|
||||
return StorageManagerIF::getData(storeId, accessor);
|
||||
}
|
||||
|
||||
ReturnValue_t LocalPool::modifyData(store_address_t storeId, StorageAccessor& accessor) {
|
||||
return StorageManagerIF::modifyData(storeId, accessor);
|
||||
}
|
||||
|
||||
AccessorPair LocalPool::modifyData(store_address_t storeId) {
|
||||
return StorageManagerIF::modifyData(storeId);
|
||||
}
|
||||
|
@ -86,21 +86,13 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
/**
|
||||
* Documentation: See StorageManagerIF.h
|
||||
*/
|
||||
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) override;
|
||||
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size) override;
|
||||
|
||||
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) override;
|
||||
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData,
|
||||
bool ignoreFault) override;
|
||||
|
||||
ConstAccessorPair getData(store_address_t storeId) override;
|
||||
ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& accessor) override;
|
||||
ReturnValue_t getData(store_address_t storeId, const uint8_t** packet_ptr, size_t* size) override;
|
||||
|
||||
AccessorPair modifyData(store_address_t storeId) override;
|
||||
ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr, size_t* size) override;
|
||||
ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) override;
|
||||
|
||||
ReturnValue_t deleteData(store_address_t storeId) override;
|
||||
ReturnValue_t deleteData(uint8_t* ptr, size_t size, store_address_t* storeId) override;
|
||||
@ -136,6 +128,12 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
[[nodiscard]] max_subpools_t getNumberOfSubPools() const override;
|
||||
[[nodiscard]] bool hasDataAtId(store_address_t storeId) const override;
|
||||
|
||||
// Using functions provided by StorageManagerIF requires either a fully qualified path
|
||||
// like for example localPool.StorageManagerIF::getFreeElement(...) or re-exporting
|
||||
// the fully qualified path with the using directive.
|
||||
using StorageManagerIF::getData;
|
||||
using StorageManagerIF::modifyData;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* With this helper method, a free element of @c size is reserved.
|
||||
@ -144,7 +142,7 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
* @return - returnvalue::OK on success,
|
||||
* - the return codes of #getPoolIndex or #findEmpty otherwise.
|
||||
*/
|
||||
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault);
|
||||
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address);
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -188,6 +186,8 @@ class LocalPool : public SystemObject, public StorageManagerIF {
|
||||
std::vector<std::vector<size_type>> sizeLists =
|
||||
std::vector<std::vector<size_type>>(NUMBER_OF_SUBPOOLS);
|
||||
|
||||
bool ignoreFault = false;
|
||||
|
||||
//! A variable to determine whether higher n pools are used if
|
||||
//! the store is full.
|
||||
bool spillsToHigherPools = false;
|
||||
|
@ -9,10 +9,9 @@ PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPo
|
||||
|
||||
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
|
||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address,
|
||||
bool ignoreFault) {
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
|
||||
ReturnValue_t status = LocalPool::reserveSpace(size, address, ignoreFault);
|
||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
|
||||
ReturnValue_t status = LocalPool::reserveSpace(size, address);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -23,12 +22,12 @@ ReturnValue_t PoolManager::deleteData(store_address_t storeId) {
|
||||
<< storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
|
||||
return LocalPool::deleteData(storeId);
|
||||
}
|
||||
|
||||
ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) {
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
|
||||
ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId);
|
||||
return status;
|
||||
}
|
||||
|
@ -56,8 +56,9 @@ class PoolManager : public LocalPool {
|
||||
protected:
|
||||
//! Default mutex timeout value to prevent permanent blocking.
|
||||
uint32_t mutexTimeoutMs = 20;
|
||||
static constexpr char LOCK_CTX[] = "PoolManager";
|
||||
|
||||
ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault) override;
|
||||
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;
|
||||
|
||||
/**
|
||||
* @brief The mutex is created in the constructor and makes
|
||||
|
@ -55,7 +55,7 @@ class StorageManagerIF {
|
||||
/**
|
||||
* @brief This is the empty virtual destructor as required for C++ interfaces.
|
||||
*/
|
||||
~StorageManagerIF() = default;
|
||||
virtual ~StorageManagerIF() = default;
|
||||
/**
|
||||
* @brief With addData, a free storage position is allocated and data
|
||||
* stored there.
|
||||
@ -66,12 +66,7 @@ class StorageManagerIF {
|
||||
* @return Returns @returnvalue::OK if data was added.
|
||||
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
|
||||
*/
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size,
|
||||
bool ignoreFault) = 0;
|
||||
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) {
|
||||
return addData(storageId, data, size, false);
|
||||
}
|
||||
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* @brief With deleteData, the storageManager frees the memory region
|
||||
@ -186,12 +181,8 @@ class StorageManagerIF {
|
||||
* @return Returns @returnvalue::OK if data was added.
|
||||
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
|
||||
*/
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr,
|
||||
bool ignoreFault) = 0;
|
||||
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr) {
|
||||
return getFreeElement(storageId, size, dataPtr, false);
|
||||
}
|
||||
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size,
|
||||
uint8_t** dataPtr) = 0;
|
||||
|
||||
[[nodiscard]] virtual bool hasDataAtId(store_address_t storeId) const = 0;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE Subsystem.cpp SubsystemBase.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE Subsystem.cpp SubsystemBase.cpp
|
||||
helper.cpp)
|
||||
|
||||
add_subdirectory(modes)
|
||||
|
13
src/fsfw/subsystem/HasModeTreeChildrenIF.h
Normal file
13
src/fsfw/subsystem/HasModeTreeChildrenIF.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
||||
#define FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
||||
|
||||
#include "ModeTreeChildIF.h"
|
||||
|
||||
class HasModeTreeChildrenIF {
|
||||
public:
|
||||
virtual ~HasModeTreeChildrenIF() = default;
|
||||
virtual ReturnValue_t registerChild(const ModeTreeChildIF& child) = 0;
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
};
|
||||
|
||||
#endif // FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
15
src/fsfw/subsystem/ModeTreeChildIF.h
Normal file
15
src/fsfw/subsystem/ModeTreeChildIF.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef FSFW_SUBSYSTEM_MODETREECHILDIF_H_
|
||||
#define FSFW_SUBSYSTEM_MODETREECHILDIF_H_
|
||||
|
||||
#include <fsfw/health/HasHealthIF.h>
|
||||
#include <fsfw/modes/HasModesIF.h>
|
||||
|
||||
class ModeTreeChildIF {
|
||||
public:
|
||||
virtual ~ModeTreeChildIF() = default;
|
||||
virtual object_id_t getObjectId() const = 0;
|
||||
virtual const HasHealthIF* getOptHealthIF() const = 0;
|
||||
virtual const HasModesIF& getModeIF() const = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SUBSYSTEM_MODETREECHILDIF_H_ */
|
13
src/fsfw/subsystem/ModeTreeConnectionIF.h
Normal file
13
src/fsfw/subsystem/ModeTreeConnectionIF.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_
|
||||
#define FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_
|
||||
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
|
||||
class ModeTreeConnectionIF {
|
||||
public:
|
||||
virtual ~ModeTreeConnectionIF() = default;
|
||||
virtual ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) = 0;
|
||||
virtual ModeTreeChildIF& getModeTreeChildIF() = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_ */
|
@ -9,9 +9,9 @@
|
||||
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||
#include "fsfw/serialize/SerializeElement.h"
|
||||
|
||||
Subsystem::Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences,
|
||||
Subsystem::Subsystem(object_id_t setObjectId, uint32_t maxNumberOfSequences,
|
||||
uint32_t maxNumberOfTables)
|
||||
: SubsystemBase(setObjectId, parent, 0),
|
||||
: SubsystemBase(setObjectId, 0),
|
||||
isInTransition(false),
|
||||
childrenChangedHealth(false),
|
||||
currentTargetTable(),
|
||||
@ -36,6 +36,13 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
|
||||
|
||||
for (; iter.value != nullptr; ++iter) {
|
||||
if (!existsModeTable(iter->getTableId())) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
using namespace std;
|
||||
sif::warning << "Subsystem::checkSequence: "
|
||||
<< "Object " << setfill('0') << hex << "0x" << setw(8) << getObjectId()
|
||||
<< setw(0) << ": Mode table for mode ID "
|
||||
<< "0x" << setw(8) << iter->getTableId() << " does not exist" << dec << endl;
|
||||
#endif
|
||||
return TABLE_DOES_NOT_EXIST;
|
||||
} else {
|
||||
ReturnValue_t result = checkTable(getTable(iter->getTableId()));
|
||||
|
@ -66,8 +66,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
* @param maxNumberOfSequences
|
||||
* @param maxNumberOfTables
|
||||
*/
|
||||
Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences,
|
||||
uint32_t maxNumberOfTables);
|
||||
Subsystem(object_id_t setObjectId, uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables);
|
||||
virtual ~Subsystem();
|
||||
|
||||
ReturnValue_t addSequence(SequenceEntry sequence);
|
||||
|
@ -1,16 +1,17 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode,
|
||||
SubsystemBase::SubsystemBase(object_id_t setObjectId, Mode_t initialMode,
|
||||
uint16_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
mode(initialMode),
|
||||
healthHelper(this, setObjectId),
|
||||
modeHelper(this),
|
||||
parentId(parent) {
|
||||
modeHelper(this) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
@ -18,38 +19,9 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
|
||||
|
||||
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
|
||||
ChildInfo info;
|
||||
|
||||
HasModesIF* child = ObjectManager::instance()->get<HasModesIF>(objectId);
|
||||
// This is a rather ugly hack to have the changedHealth info for all
|
||||
// children available.
|
||||
HasHealthIF* healthChild = ObjectManager::instance()->get<HasHealthIF>(objectId);
|
||||
if (child == nullptr) {
|
||||
if (healthChild == nullptr) {
|
||||
return CHILD_DOESNT_HAVE_MODES;
|
||||
} else {
|
||||
info.commandQueue = healthChild->getCommandQueue();
|
||||
info.mode = MODE_OFF;
|
||||
}
|
||||
} else {
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = child->getCommandQueue();
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
}
|
||||
|
||||
info.submode = SUBMODE_NONE;
|
||||
info.healthChanged = false;
|
||||
|
||||
auto resultPair = childrenMap.emplace(objectId, info);
|
||||
if (not resultPair.second) {
|
||||
return COULD_NOT_INSERT_CHILD;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
||||
Submode_t targetSubmode) {
|
||||
using namespace mode;
|
||||
std::map<object_id_t, ChildInfo>::iterator childIter;
|
||||
|
||||
for (; tableIter.value != NULL; ++tableIter) {
|
||||
@ -63,13 +35,21 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
Submode_t submodeToCheckAgainst = tableIter.value->getSubmode();
|
||||
// Check submodes here.
|
||||
uint8_t mask;
|
||||
bool submodesAllowedMask = tableIter.value->submodesAllowed(&mask);
|
||||
uint8_t submodeToCheckAgainst = tableIter.value->getSubmode();
|
||||
if (tableIter.value->inheritSubmode()) {
|
||||
submodeToCheckAgainst = targetSubmode;
|
||||
}
|
||||
|
||||
if (childIter->second.submode != submodeToCheckAgainst) {
|
||||
return returnvalue::FAILED;
|
||||
if (submodesAllowedMask) {
|
||||
if ((childIter->second.submode | mask) != mask) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
} else {
|
||||
if (childIter->second.submode != submodeToCheckAgainst) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
@ -87,7 +67,8 @@ void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submod
|
||||
if ((iter = childrenMap.find(object)) == childrenMap.end()) {
|
||||
// illegal table entry, should only happen due to misconfigured mode table
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << std::hex << getObjectId() << ": invalid mode table entry" << std::endl;
|
||||
sif::debug << std::hex << SystemObject::getObjectId() << ": invalid mode table entry"
|
||||
<< std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
@ -145,6 +126,20 @@ ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, Mode_t mode
|
||||
return CHILD_NOT_FOUND;
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::updateChildModeByObjId(object_id_t objectId, Mode_t mode,
|
||||
Submode_t submode) {
|
||||
std::map<object_id_t, ChildInfo>::iterator iter;
|
||||
|
||||
for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
|
||||
if (iter->first == objectId) {
|
||||
iter->second.mode = mode;
|
||||
iter->second.submode = submode;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
}
|
||||
return CHILD_NOT_FOUND;
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth) {
|
||||
for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) {
|
||||
if (iter->second.commandQueue == queue) {
|
||||
@ -158,36 +153,15 @@ ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bo
|
||||
MessageQueueId_t SubsystemBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
|
||||
ReturnValue_t SubsystemBase::initialize() {
|
||||
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::performOperation(uint8_t opCode) {
|
||||
@ -240,8 +214,14 @@ ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) {
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::checkTable(HybridIterator<ModeListEntry> tableIter) {
|
||||
for (; tableIter.value != NULL; ++tableIter) {
|
||||
for (; tableIter.value != nullptr; ++tableIter) {
|
||||
if (childrenMap.find(tableIter.value->getObject()) == childrenMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
using namespace std;
|
||||
sif::warning << "SubsystemBase::checkTable: Could not find object " << setfill('0') << hex
|
||||
<< "0x" << setw(8) << tableIter.value->getObject() << " in object " << setw(8)
|
||||
<< setw(0) << "0x" << setw(8) << SystemObject::getObjectId() << dec << std::endl;
|
||||
#endif
|
||||
return TABLE_CONTAINS_INVALID_OBJECT_ID;
|
||||
}
|
||||
}
|
||||
@ -326,4 +306,33 @@ ReturnValue_t SubsystemBase::setHealth(HealthState health) {
|
||||
|
||||
HasHealthIF::HealthState SubsystemBase::getHealth() { return healthHelper.getHealth(); }
|
||||
|
||||
ReturnValue_t SubsystemBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
void SubsystemBase::modeChanged() {}
|
||||
|
||||
ReturnValue_t SubsystemBase::registerChild(const ModeTreeChildIF& child) {
|
||||
ChildInfo info;
|
||||
|
||||
const HasModesIF& modeChild = child.getModeIF();
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = modeChild.getCommandQueue();
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
info.submode = SUBMODE_NONE;
|
||||
info.healthChanged = false;
|
||||
|
||||
auto resultPair = childrenMap.emplace(child.getObjectId(), info);
|
||||
if (not resultPair.second) {
|
||||
return COULD_NOT_INSERT_CHILD;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& SubsystemBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& SubsystemBase::getModeTreeChildIF() { return *this; }
|
||||
|
@ -3,14 +3,16 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../container/HybridIterator.h"
|
||||
#include "../health/HasHealthIF.h"
|
||||
#include "../health/HealthHelper.h"
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../modes/HasModesIF.h"
|
||||
#include "../objectmanager/SystemObject.h"
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/container/HybridIterator.h"
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "modes/HasModeSequenceIF.h"
|
||||
|
||||
/**
|
||||
@ -27,6 +29,9 @@
|
||||
class SubsystemBase : public SystemObject,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasModeTreeChildrenIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ModeTreeChildIF,
|
||||
public ExecutableObjectIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM_BASE;
|
||||
@ -36,32 +41,34 @@ class SubsystemBase : public SystemObject,
|
||||
static const ReturnValue_t COULD_NOT_INSERT_CHILD = MAKE_RETURN_CODE(0x04);
|
||||
static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = MAKE_RETURN_CODE(0x05);
|
||||
|
||||
SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode = 0,
|
||||
uint16_t commandQueueDepth = 8);
|
||||
SubsystemBase(object_id_t setObjectId, Mode_t initialMode = 0, uint16_t commandQueueDepth = 8);
|
||||
virtual ~SubsystemBase();
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* Function to register the child objects.
|
||||
* Performs a checks if the child does implement HasHealthIF and/or HasModesIF
|
||||
*
|
||||
* Also adds them to the internal childrenMap.
|
||||
* Also adds them to the internal childrenMap.
|
||||
*
|
||||
* @param objectId
|
||||
* @return returnvalue::OK if successful
|
||||
* CHILD_DOESNT_HAVE_MODES if Child is no HasHealthIF and no HasModesIF
|
||||
* COULD_NOT_INSERT_CHILD If the Child could not be added to the ChildrenMap
|
||||
* CHILD_DOESNT_HAVE_MODES if Child is no HasHealthIF and no HasModesIF
|
||||
* COULD_NOT_INSERT_CHILD If the Child could not be added to the ChildrenMap
|
||||
*/
|
||||
ReturnValue_t registerChild(object_id_t objectId);
|
||||
ReturnValue_t registerChild(const ModeTreeChildIF &child) override;
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
|
||||
virtual HasHealthIF::HealthState getHealth() override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
protected:
|
||||
struct ChildInfo {
|
||||
@ -88,8 +95,6 @@ class SubsystemBase : public SystemObject,
|
||||
|
||||
ModeHelper modeHelper;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
typedef std::map<object_id_t, ChildInfo> ChildrenMap;
|
||||
ChildrenMap childrenMap;
|
||||
|
||||
@ -110,6 +115,7 @@ class SubsystemBase : public SystemObject,
|
||||
Submode_t targetSubmode = SUBMODE_NONE);
|
||||
|
||||
ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, Submode_t submode);
|
||||
ReturnValue_t updateChildModeByObjId(object_id_t objectId, Mode_t mode, Submode_t submode);
|
||||
|
||||
ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth = true);
|
||||
|
||||
@ -136,6 +142,10 @@ class SubsystemBase : public SystemObject,
|
||||
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
|
||||
object_id_t getObjectId() const override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
virtual void setToExternalControl() override;
|
||||
|
||||
virtual void announceMode(bool recursive) override;
|
||||
|
15
src/fsfw/subsystem/helper.cpp
Normal file
15
src/fsfw/subsystem/helper.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "helper.h"
|
||||
|
||||
ReturnValue_t modetree::connectModeTreeParent(HasModeTreeChildrenIF& parent,
|
||||
const ModeTreeChildIF& child,
|
||||
HealthHelper* healthHelper, ModeHelper& modeHelper) {
|
||||
ReturnValue_t result = parent.registerChild(child);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (healthHelper != nullptr) {
|
||||
healthHelper->setParentQueue(parent.getCommandQueue());
|
||||
}
|
||||
modeHelper.setParentQueue(parent.getCommandQueue());
|
||||
return returnvalue::OK;
|
||||
}
|
14
src/fsfw/subsystem/helper.h
Normal file
14
src/fsfw/subsystem/helper.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_SUBSYSTEM_HELPER_H_
|
||||
#define FSFW_SUBSYSTEM_HELPER_H_
|
||||
|
||||
#include "HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
|
||||
namespace modetree {
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent, const ModeTreeChildIF& child,
|
||||
HealthHelper* healthHelper, ModeHelper& modeHelper);
|
||||
|
||||
}
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_SUBSYSTEM_HELPER_H_ */
|
@ -1,111 +1,126 @@
|
||||
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||
|
||||
#include "../../modes/HasModesIF.h"
|
||||
#include "../../objectmanager/SystemObjectIF.h"
|
||||
#include "../../serialize/SerialLinkedListAdapter.h"
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
class ModeListEntry : public SerializeIF, public LinkedElement<ModeListEntry> {
|
||||
namespace mode {
|
||||
enum SpecialSubmodeFlags : uint8_t { INHERIT = 1 << 0, ALLOWED_MASK = 1 << 1 };
|
||||
}
|
||||
|
||||
class ModeListEntry : public SerialLinkedListAdapter<SerializeIF>,
|
||||
public LinkedElement<ModeListEntry> {
|
||||
public:
|
||||
ModeListEntry() : LinkedElement<ModeListEntry>(this) {}
|
||||
static constexpr uint8_t ALL_SUBMODES_ALLOWED_MASK = 0xff;
|
||||
|
||||
uint32_t value1 = 0;
|
||||
uint32_t value2 = 0;
|
||||
uint8_t value3 = 0;
|
||||
uint8_t value4 = 0;
|
||||
ModeListEntry() : SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) { setLinks(); }
|
||||
|
||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result;
|
||||
SerializeElement<uint32_t> value1 = 0;
|
||||
SerializeElement<uint32_t> value2 = 0;
|
||||
SerializeElement<uint8_t> value3 = 0;
|
||||
SerializeElement<uint8_t> value4 = 0;
|
||||
SerializeElement<uint8_t> value5 = 0;
|
||||
|
||||
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&value2, buffer, size, maxSize, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::serialize(&value3, buffer, size, maxSize, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SerializeAdapter::serialize(&value4, buffer, size, maxSize, streamEndianness);
|
||||
|
||||
return result;
|
||||
ModeListEntry(const ModeListEntry& other)
|
||||
: SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) {
|
||||
value1.entry = other.value1.entry;
|
||||
value2.entry = other.value2.entry;
|
||||
value3.entry = other.value3.entry;
|
||||
value4.entry = other.value4.entry;
|
||||
value5.entry = other.value5.entry;
|
||||
setLinks();
|
||||
}
|
||||
|
||||
virtual size_t getSerializedSize() const {
|
||||
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
|
||||
ModeListEntry& operator=(const ModeListEntry& other) {
|
||||
this->value1.entry = other.value1.entry;
|
||||
this->value2.entry = other.value2.entry;
|
||||
this->value3.entry = other.value3.entry;
|
||||
this->value4.entry = other.value4.entry;
|
||||
this->value5.entry = other.value5.entry;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) {
|
||||
ReturnValue_t result;
|
||||
|
||||
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&value2, buffer, size, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&value3, buffer, size, streamEndianness);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = SerializeAdapter::deSerialize(&value4, buffer, size, streamEndianness);
|
||||
|
||||
return result;
|
||||
void setLinks() {
|
||||
setStart(&value1);
|
||||
value1.setNext(&value2);
|
||||
value2.setNext(&value3);
|
||||
value3.setNext(&value4);
|
||||
value4.setNext(&value5);
|
||||
}
|
||||
|
||||
// for Sequences
|
||||
Mode_t getTableId() const { return value1; }
|
||||
Mode_t getTableId() const { return value1.entry; }
|
||||
|
||||
void setTableId(Mode_t tableId) { this->value1 = tableId; }
|
||||
void setTableId(Mode_t tableId) { this->value1.entry = tableId; }
|
||||
|
||||
uint8_t getWaitSeconds() const { return value2; }
|
||||
uint8_t getWaitSeconds() const { return value2.entry; }
|
||||
|
||||
void setWaitSeconds(uint8_t waitSeconds) { this->value2 = waitSeconds; }
|
||||
void setWaitSeconds(uint8_t waitSeconds) { this->value2.entry = waitSeconds; }
|
||||
|
||||
bool checkSuccess() const { return value3 == 1; }
|
||||
bool checkSuccess() const { return value3.entry == 1; }
|
||||
|
||||
void setCheckSuccess(bool checkSuccess) { this->value3 = checkSuccess; }
|
||||
void setCheckSuccess(bool checkSuccess) { this->value3.entry = checkSuccess; }
|
||||
|
||||
// for Tables
|
||||
object_id_t getObject() const { return value1; }
|
||||
object_id_t getObject() const { return value1.entry; }
|
||||
|
||||
void setObject(object_id_t object) { this->value1 = object; }
|
||||
void setObject(object_id_t object) { this->value1.entry = object; }
|
||||
|
||||
Mode_t getMode() const { return value2; }
|
||||
Mode_t getMode() const { return value2.entry; }
|
||||
|
||||
void setMode(Mode_t mode) { this->value2 = mode; }
|
||||
void setMode(Mode_t mode) { this->value2.entry = mode; }
|
||||
|
||||
Submode_t getSubmode() const { return value3; }
|
||||
Submode_t getSubmode() const { return value3.entry; }
|
||||
|
||||
void setSubmode(Submode_t submode) { this->value3 = submode; }
|
||||
void setSubmode(Submode_t submode) { this->value3.entry = submode; }
|
||||
|
||||
bool inheritSubmode() const { return value4 == 1; }
|
||||
|
||||
void setInheritSubmode(bool inherit) {
|
||||
if (inherit) {
|
||||
value4 = 1;
|
||||
} else {
|
||||
value4 = 0;
|
||||
bool inheritSubmode() const {
|
||||
return (value4.entry & mode::SpecialSubmodeFlags::INHERIT) ==
|
||||
mode::SpecialSubmodeFlags::INHERIT;
|
||||
}
|
||||
bool submodesAllowed(uint8_t* mask) const {
|
||||
bool submodesAllowed = (value4.entry & mode::SpecialSubmodeFlags::ALLOWED_MASK) ==
|
||||
mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||
if (submodesAllowed and mask != nullptr) {
|
||||
*mask = value5.entry;
|
||||
}
|
||||
return submodesAllowed;
|
||||
}
|
||||
|
||||
bool operator==(ModeListEntry other) {
|
||||
return ((value1 == other.value1) && (value2 == other.value2) && (value3 == other.value3));
|
||||
/**
|
||||
* Enable the inheritance of submodes. This is relevant for both the execution
|
||||
* of mode tables and for mode checking.
|
||||
*/
|
||||
void enableInheritSubmode() { value4.entry |= mode::SpecialSubmodeFlags::INHERIT; }
|
||||
/**
|
||||
* Disable the inheritance of submodes. This is relevant for both the execution
|
||||
* of mode tables and for mode checking.
|
||||
*/
|
||||
void disableInheritSubmode() { value4.entry &= ~mode::SpecialSubmodeFlags::INHERIT; }
|
||||
|
||||
/**
|
||||
* Specialization of @enableSubmodeAllowed which allows all submodes.
|
||||
*/
|
||||
void allowAllSubmodes() { enableSubmodeAllowed(ALL_SUBMODES_ALLOWED_MASK); }
|
||||
|
||||
/**
|
||||
* Enable an allowed submode mask for mode checks. Any submode which contains bits
|
||||
* outside of the mask will be declined.
|
||||
*
|
||||
* For example, for a mask of 0b11, only the modes 0b00, 0b01 and 0b11 will be accepted.
|
||||
*/
|
||||
void enableSubmodeAllowed(uint8_t mask) {
|
||||
value4.entry |= mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||
value5.entry = mask;
|
||||
}
|
||||
/**
|
||||
* Enforce the equality of submodes for mode checks. This is the default.
|
||||
*/
|
||||
void disableSubmodeAllowed() {
|
||||
value4.entry &= ~mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||
value5.entry = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -15,10 +15,10 @@ ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjec
|
||||
uint32_t slotTimeMs, int8_t executionStep) {
|
||||
if (execObj == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execObj
|
||||
sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execId
|
||||
<< std::setfill(' ') << " 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");
|
||||
sif::printError("Component 0x%08x not found, not adding it to PST\n", execId);
|
||||
#endif
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
}
|
||||
switch (uniqueId) {
|
||||
case 0:
|
||||
parameterWrapper->set(heaterOnCountdown.timeout);
|
||||
parameterWrapper->set(heaterOnCountdown.getTimeoutMs());
|
||||
break;
|
||||
default:
|
||||
return INVALID_IDENTIFIER_ID;
|
||||
|
@ -246,6 +246,20 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t*
|
||||
return UNSUPPORTED_TIME_FORMAT;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::convertToAsciiWithSecs(int8_t* to, const Clock::TimeOfDay_t* from,
|
||||
uint8_t length) {
|
||||
if (from == nullptr or to == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
int count = snprintf(reinterpret_cast<char*>(to), length,
|
||||
"%4" SCNu32 "-%2" SCNu32 "-%2" SCNu32 "T%2" SCNu32 ":%2" SCNu32 ":%2" SCNu32,
|
||||
from->year, from->month, from->day, from->hour, from->minute, from->second);
|
||||
if (count >= length) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) {
|
||||
const Ccs_mseconds* time_struct = reinterpret_cast<const Ccs_mseconds*>(time);
|
||||
|
||||
|
@ -207,7 +207,8 @@ class CCSDSTime {
|
||||
|
||||
static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from,
|
||||
uint8_t length);
|
||||
|
||||
static ReturnValue_t convertToAsciiWithSecs(int8_t *to, const Clock::TimeOfDay_t *from,
|
||||
uint8_t length);
|
||||
static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
|
||||
|
||||
private:
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
|
||||
CdsShortTimeStamper::CdsShortTimeStamper() : SystemObject(0, false) {}
|
||||
|
||||
CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {}
|
||||
|
||||
ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
|
@ -18,6 +18,7 @@
|
||||
class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject {
|
||||
public:
|
||||
static constexpr size_t TIMESTAMP_LEN = 7;
|
||||
CdsShortTimeStamper();
|
||||
/**
|
||||
* @brief Default constructor which also registers the time stamper as a
|
||||
* system object so it can be found with the #objectManager.
|
||||
|
@ -49,6 +49,13 @@ class Clock {
|
||||
* @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
||||
*/
|
||||
static ReturnValue_t setClock(const timeval *time);
|
||||
|
||||
/**
|
||||
* @deprecated Use getClock instead, which does the same.
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t getClock_timeval(timeval *time);
|
||||
/**
|
||||
* This system call returns the current system clock in timeval format.
|
||||
* The timval format has the fields @c tv_sec with seconds and @c tv_usec with
|
||||
@ -56,7 +63,18 @@ class Clock {
|
||||
* @param time A pointer to a timeval struct where the current time is stored.
|
||||
* @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned.
|
||||
*/
|
||||
static ReturnValue_t getClock_timeval(timeval *time);
|
||||
static ReturnValue_t getClock(timeval *time);
|
||||
|
||||
/**
|
||||
* Retrieve a monotonic clock. This clock this is also more suited for measuring elapsed times
|
||||
* between two time points, but less suited when the absolute time is required.
|
||||
*
|
||||
* Implementation example: A generic UNIX implementation can use CLOCK_MONOTONIC_RAW with
|
||||
* `clock_gettime`.
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
static ReturnValue_t getClockMonotonic(timeval *time);
|
||||
|
||||
/**
|
||||
* Get the time since boot in a timeval struct
|
||||
|
@ -1,49 +1,62 @@
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
||||
#include "fsfw/globalfunctions/timevalOperations.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) {
|
||||
if (startImmediately) {
|
||||
setTimeout(initialTimeout);
|
||||
} else {
|
||||
timeout = initialTimeout;
|
||||
timeout.tv_sec = initialTimeout / 1000;
|
||||
timeout.tv_usec = (initialTimeout % 1000) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
Countdown::~Countdown() {}
|
||||
Countdown::~Countdown() = default;
|
||||
|
||||
ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) {
|
||||
ReturnValue_t returnValue = Clock::getUptime(&startTime);
|
||||
timeout = milliseconds;
|
||||
return returnValue;
|
||||
timeout.tv_sec = milliseconds / 1000;
|
||||
timeout.tv_usec = (milliseconds % 1000) * 1000;
|
||||
return Clock::getClockMonotonic(&startTime);
|
||||
}
|
||||
|
||||
bool Countdown::hasTimedOut() const {
|
||||
if (uint32_t(this->getCurrentTime() - startTime) >= timeout) {
|
||||
// Account for system clock going back in time.
|
||||
if (getCurrentTime() < startTime) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (getCurrentTime() - startTime >= timeout) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Countdown::isBusy() const { return !hasTimedOut(); }
|
||||
|
||||
ReturnValue_t Countdown::resetTimer() { return setTimeout(timeout); }
|
||||
ReturnValue_t Countdown::resetTimer() { return setTimeoutTv(timeout); }
|
||||
|
||||
void Countdown::timeOut() { startTime = this->getCurrentTime() - timeout; }
|
||||
|
||||
uint32_t Countdown::getRemainingMillis() const {
|
||||
// We fetch the time before the if-statement
|
||||
// to be sure that the return is in
|
||||
// range 0 <= number <= timeout
|
||||
uint32_t currentTime = this->getCurrentTime();
|
||||
if (this->hasTimedOut()) {
|
||||
return 0;
|
||||
} else {
|
||||
return (startTime + timeout) - currentTime;
|
||||
}
|
||||
timeval remainingMillisTv = (startTime + timeout) - this->getCurrentTime();
|
||||
return remainingMillisTv.tv_sec * 1000 + remainingMillisTv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
uint32_t Countdown::getCurrentTime() const {
|
||||
uint32_t currentTime;
|
||||
Clock::getUptime(¤tTime);
|
||||
uint32_t Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_usec / 1000; }
|
||||
|
||||
ReturnValue_t Countdown::setTimeoutTv(timeval tv) {
|
||||
timeout = tv;
|
||||
return Clock::getClockMonotonic(&startTime);
|
||||
}
|
||||
|
||||
uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; }
|
||||
|
||||
timeval Countdown::getTimeout() const { return timeout; }
|
||||
|
||||
timeval Countdown::getCurrentTime() const {
|
||||
timeval currentTime{};
|
||||
Clock::getClockMonotonic(¤tTime);
|
||||
return currentTime;
|
||||
}
|
||||
|
@ -6,6 +6,10 @@
|
||||
/**
|
||||
*
|
||||
* Countdown keeps track of a timespan.
|
||||
* This class uses the system clock internally to achieve
|
||||
* a high resolution. This means that the API is only partially
|
||||
* resistant against time jumps. The user must take care to account
|
||||
* for time jumps in some from if this relevant.
|
||||
*
|
||||
* Countdown::resetTimer restarts the timer.
|
||||
* Countdown::setTimeout sets a new countdown duration and resets.
|
||||
@ -39,6 +43,8 @@ class Countdown {
|
||||
* @return Returnvalue from Clock::getUptime
|
||||
*/
|
||||
ReturnValue_t setTimeout(uint32_t milliseconds);
|
||||
ReturnValue_t setTimeoutTv(timeval tv);
|
||||
|
||||
/**
|
||||
* Returns true if the countdown duration has passed.
|
||||
*
|
||||
@ -61,22 +67,31 @@ class Countdown {
|
||||
* Returns the remaining milliseconds (0 if timeout)
|
||||
*/
|
||||
uint32_t getRemainingMillis() const;
|
||||
|
||||
uint32_t getTimeoutMs() const;
|
||||
|
||||
timeval getTimeout() const;
|
||||
|
||||
/**
|
||||
* Makes hasTimedOut() return true
|
||||
*/
|
||||
void timeOut();
|
||||
/**
|
||||
* Internal countdown duration in milliseconds
|
||||
*/
|
||||
uint32_t timeout;
|
||||
|
||||
static inline uint32_t timevalToMs(timeval& tv);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Last time the timer was started (uptime)
|
||||
* Start time of the countdown.
|
||||
*/
|
||||
uint32_t startTime = 0;
|
||||
timeval startTime{};
|
||||
|
||||
uint32_t getCurrentTime() const;
|
||||
/**
|
||||
* Timeout as timeval type. The countdown has timed out when the
|
||||
* current time exceeds the start time plus the timeout.
|
||||
*/
|
||||
timeval timeout{};
|
||||
|
||||
timeval getCurrentTime() const;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */
|
||||
|
@ -9,10 +9,10 @@
|
||||
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
|
||||
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
|
||||
// Measures start time on initialization.
|
||||
Clock::getUptime(&startTime);
|
||||
Clock::getClockMonotonic(&startTime);
|
||||
}
|
||||
|
||||
void Stopwatch::start() { Clock::getUptime(&startTime); }
|
||||
void Stopwatch::start() { Clock::getClockMonotonic(&startTime); }
|
||||
|
||||
dur_millis_t Stopwatch::stop(bool display) {
|
||||
stopInternal();
|
||||
@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
|
||||
|
||||
void Stopwatch::stopInternal() {
|
||||
timeval endTime;
|
||||
Clock::getUptime(&endTime);
|
||||
Clock::getClockMonotonic(&endTime);
|
||||
elapsedTime = endTime - startTime;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef FSFW_TIMEMANAGER_TIMEREADERIF_H
|
||||
#define FSFW_TIMEMANAGER_TIMEREADERIF_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "fsfw/platform.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user