Compare commits
266 Commits
tmtcbridge
...
develop_up
Author | SHA1 | Date | |
---|---|---|---|
a837a78bd4 | |||
d246ce34d0 | |||
796c7a9e37 | |||
d575da8540 | |||
62ace649a7
|
|||
aac74fae38
|
|||
a26b0c38ac
|
|||
42e74d22cc | |||
36caa58043 | |||
988e07f0be
|
|||
88e8665280
|
|||
9c8b1c697b
|
|||
110cb903a6
|
|||
8da89eba80 | |||
7e8845f2c2 | |||
6aff3250c2 | |||
c3572e31a8
|
|||
2293e7f2bb | |||
a85a38c882 | |||
0f76cdb3ba | |||
268c2e87c9 | |||
87f94a252f | |||
c7037d417a | |||
f80c5980ea | |||
ad01642fee | |||
f2947bc78e | |||
0a977ea688 | |||
74b164b1da | |||
5322de0599 | |||
9a4bf51006 | |||
3a70229510 | |||
b3beedad9f | |||
efe217a197 | |||
b442ca09b9 | |||
9372b2a575 | |||
aafa53148e | |||
e0adb3325f | |||
4391823f01 | |||
1a77e6bb09 | |||
cae131edcf | |||
4518fec65c | |||
dac1aacab2 | |||
0042f92fdf | |||
656faf8169 | |||
f84431e965 | |||
0cec9ebb73 | |||
a440b7c394 | |||
bbfc1b2b34 | |||
025b379e8b
|
|||
258f0d3313 | |||
5eb9ee8bc1 | |||
7f61d17cee | |||
ffa2fa477f | |||
894d1e3b87 | |||
285d327b97 | |||
e97fa5ac84 | |||
5a9304765f | |||
6650c293da | |||
9fca7581dd | |||
4af90f99f3 | |||
94cdf67a80 | |||
7966ede11b | |||
7a392dc33a | |||
1e3c89b672 | |||
e2e87b149d | |||
4f632e2c68 | |||
314f0fa2cd | |||
b31e1037fb | |||
b814e7198f | |||
6328b70d7b | |||
a937b457f9 | |||
4415dc24e1 | |||
e704295cce | |||
d16b3c7e67 | |||
3b86545725 | |||
cf6150cc18 | |||
bfb5c2ff03 | |||
bf02061d47 | |||
2c4e110254 | |||
7ed75ea87b | |||
db4587bb59 | |||
33ac395072 | |||
f8a7c1d4ed | |||
341437df13 | |||
227524a21d | |||
0f81d5e458 | |||
b50f092939 | |||
2f90e12179 | |||
8b77fac099 | |||
47503824d7 | |||
5e3f5c4121 | |||
1f36c082ef | |||
aa84e93603 | |||
8f63a0e747 | |||
6fc8f756a7 | |||
d98ed40e3d | |||
b057250bfb | |||
066dd0d397 | |||
f735c2e9d4 | |||
54ef9ec3f6 | |||
43fd0b2f59 | |||
d0607824ad | |||
cf27954a86 | |||
f84e3284ab | |||
5250423d1d | |||
522bd41d6e | |||
c61c85280b | |||
afbe5e1f65 | |||
4c88ab80c8 | |||
5ba69b169f | |||
40405fe6c7 | |||
aac32e763c | |||
bf980d74c0 | |||
b6b9d1d790 | |||
0973ba6bf2 | |||
1cfebb5d47 | |||
0b0a0299bc | |||
8382d61b92 | |||
7208343b6d | |||
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 | |||
dc7afc5415 | |||
9bf3ff95b7 | |||
61562b18ab | |||
d76d97a36b | |||
d373c45d36 | |||
bd208038dd | |||
206af00c8b | |||
2efff4d2c5 | |||
2a0c244468 | |||
e1711f0345 | |||
c327985222 | |||
76b377c4c0 | |||
b45206ccd6 | |||
c8469ca647 | |||
2d6622b8b8 | |||
5f9eb01d94 | |||
3568bdbecf | |||
fcd84b59ae | |||
e3c968096b | |||
c745c0c8b4 | |||
be015b4c66 | |||
dae5e988fd | |||
a6d707a7db | |||
fe41d73895 | |||
70b785984c | |||
9de6c4b3aa | |||
d256ede8c1 | |||
f0b8457ba2 | |||
dac2d210b5 | |||
8b4f73a97b | |||
7fae6cbd6d | |||
d302ba7185 | |||
3562bf11b9 | |||
fffb2b61e5 | |||
94e5f62331 | |||
14a92b3d89 | |||
e4fd424d66 | |||
341a66c265 | |||
b9b076aa4c | |||
d93486a340 | |||
820a7f059c | |||
f4d188c36f | |||
1841f92944 | |||
b279985859 | |||
0a9c563bbc | |||
fa7675897d | |||
3a2393885f | |||
c752b6d143 | |||
b676040c7c | |||
010509efb4 | |||
dfb1633f00 | |||
5f7172e130 | |||
0c6465cd95 | |||
f94987c46d | |||
1809ce359b | |||
8c712441ab | |||
6ce80ea6c5 | |||
f1b0ca7cff | |||
000df85556 | |||
1fffcc2229 | |||
7f907fb9d3 | |||
a419806a05 | |||
134d908f26 | |||
40a9e12416 | |||
f39054edd4 | |||
5adf89b911 | |||
c2e6a22dec | |||
c8e065a713 | |||
4dc49c57d5 | |||
e9d629b9b3 | |||
3ed49dbae3 | |||
a1567de9e8 | |||
4cf52d5dfe | |||
46230e6c6d | |||
b22d439300 | |||
7e7b3bbbc9 | |||
06dca7608a | |||
6af5274b68 | |||
5b92247fbd | |||
d9da55fdab | |||
066f7a6f9b | |||
b1e9dd9e4a | |||
c1f42618db | |||
61df451dd8 | |||
29ea89044e | |||
e487f5be87 | |||
0cc3231ceb | |||
041d1b8795 | |||
48403c002d | |||
2aa4af6974 | |||
75fc7a056d | |||
1b005d706a | |||
e68f54b9bd | |||
e86d8c64db | |||
1de1b045cd | |||
296bc56e2a | |||
2b6a33e718 | |||
61fd5d1b62 | |||
046dbe1deb | |||
0303c1a885 | |||
4d2802a470 | |||
819a2bfac4 | |||
096af44e39 | |||
56e8e5a8b3 |
8
.idea/cmake.xml
generated
Normal file
8
.idea/cmake.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeSharedSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host" />
|
||||
</configurations>
|
||||
</component>
|
||||
</project>
|
155
CHANGELOG.md
155
CHANGELOG.md
@ -8,27 +8,72 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# [unreleased]
|
||||
|
||||
# [v6.0.0]
|
||||
## Fixes
|
||||
|
||||
- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source
|
||||
data with a size limited only by the size of `size_t`.
|
||||
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
|
||||
number fields stored the actual length of the field instead of the length minus 1 like specified
|
||||
in the CFDP standard.
|
||||
- PUS Health Service: Size check for set health command.
|
||||
Perform operation completion for announce health command.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
|
||||
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
|
||||
- Small tweak for version getter
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
|
||||
|
||||
## Added
|
||||
|
||||
- add CFDP subsystem ID
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||
- `PusTmZcWriter` now exposes API to set message counter field.
|
||||
|
||||
## Changed
|
||||
|
||||
- HK generation is now countdown based.
|
||||
- Bump ETL version to 20.35.14
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
|
||||
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
||||
- Assert that `FixedArrayList` is larger than 0 at compile time.
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
|
||||
- Health functions are virtual now.
|
||||
|
||||
# [v6.0.0] 2023-02-10
|
||||
|
||||
## Fixes
|
||||
|
||||
- Mode Service: Add allowed subservice
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
|
||||
- `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.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
|
||||
- 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
|
||||
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
|
||||
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||
to false correctly because the `read` and `write` calls were missing.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
|
||||
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||
of the correct unsegmented flags (0b11) as specified in the standard.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
|
||||
- TC Scheduler Service 11: Add size and CRC check for contained TC.
|
||||
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
|
||||
- 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
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710
|
||||
- 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
|
||||
@ -38,11 +83,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
||||
CCSDS packets which were clumped together. This has been fixed now.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||
- various fixes related to linux Unittests and memory leaks
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
|
||||
- small fix to allow teardown handling
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
|
||||
- fix compiler warning for fixed array list copy ctor
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
|
||||
- missing include
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
|
||||
- defaultconfig did not build anymore
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
|
||||
- hotfix
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
|
||||
- small fix for helper
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
|
||||
- missing retval conv
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
|
||||
- DHB Countdown Bug
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
|
||||
- doc corrections
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
|
||||
- better error printout
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
|
||||
- include correction
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
|
||||
- better warning for missing include paths
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
|
||||
- Service 11 regression
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
|
||||
|
||||
## Added
|
||||
|
||||
- `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
|
||||
@ -54,17 +131,36 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
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
|
||||
- publish documentation for development and master branch
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
|
||||
- Add Linux HAL options
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
|
||||
- Expand SerializeIF
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
|
||||
- PUS Service 11: Additional Safety Check
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
|
||||
- improvements for auto-formatter script
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
|
||||
- provide a weak print char impl
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
|
||||
|
||||
## Removed
|
||||
|
||||
- now that doc server is up, remove markdown files
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
|
||||
- remove bsp specific code
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
|
||||
|
||||
## 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
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||
- `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.
|
||||
so 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
|
||||
@ -94,18 +190,41 @@ 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
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||
- 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
|
||||
- Generic TMTC Bridge Update
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
||||
- comment tweak to event parser can read everything
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
|
||||
- CMakeLists file updates
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
|
||||
- improve srv20 error messages
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
|
||||
- I2C Linux: remove duplicate printout
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
|
||||
- printout handling improvements
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
|
||||
- vec getter, reset for content
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
|
||||
- updates for source sequence counter
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
|
||||
- SP reader getPacketData is const now
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
|
||||
- refactoring of serial drivers for linux
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
|
||||
- Local Pool Update Remove Add Data Ignore Fault Argument
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
|
||||
- Switch to new documentation server
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
|
||||
- Windows Tweaks
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
|
||||
- Refactor Local Pool API
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
|
||||
- group MGM data in local pool vectors
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
|
||||
|
||||
|
||||
## CFDP
|
||||
|
||||
@ -125,17 +244,7 @@ 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
|
||||
# [v5.0.0] 2022-07-25
|
||||
|
||||
## Changes
|
||||
|
||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
||||
# Version file handling #
|
||||
# ##############################################################################
|
||||
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 5)
|
||||
set(FSFW_VERSION_IF_GIT_FAILS 6)
|
||||
set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
|
||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||
|
||||
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
|
||||
20
|
||||
CACHE STRING "ETL library major version requirement")
|
||||
set(FSFW_ETL_LIB_VERSION
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
||||
${FSFW_ETL_LIB_MAJOR_VERSION}.35.14
|
||||
CACHE STRING "ETL library exact version requirement")
|
||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||
|
||||
@ -153,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)
|
||||
|
||||
@ -196,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(
|
||||
|
110
scripts/check_release.py
Executable file
110
scripts/check_release.py
Executable file
@ -0,0 +1,110 @@
|
||||
#! /bin/python
|
||||
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import urllib.request
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="List undocumented PRs"
|
||||
)
|
||||
parser.add_argument("-v", "--version", type=str, required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
|
||||
|
||||
if not match:
|
||||
print("invalid version")
|
||||
exit(1)
|
||||
|
||||
version = "v" + match.group(1)
|
||||
|
||||
print("looking for milestone for " + version + " ...")
|
||||
|
||||
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
|
||||
milestones = json.load(milestone_json)
|
||||
if (len(milestones) == 0):
|
||||
print("did not find any milestone")
|
||||
exit(1)
|
||||
if (len(milestones) > 1):
|
||||
print("found multiple milestons")
|
||||
milestone_title = milestones[0]['title']
|
||||
milestone = str(milestones[0]['id'])
|
||||
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
|
||||
|
||||
milestone_prs = []
|
||||
|
||||
page = 1
|
||||
last_count = 1;
|
||||
while last_count != 0:
|
||||
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
|
||||
pull_requests = json.load(pull_requests_json)
|
||||
for pr in pull_requests:
|
||||
milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']})
|
||||
page += 1
|
||||
last_count = len(pull_requests)
|
||||
|
||||
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
|
||||
|
||||
print("looking for CHANGELOG.md ...")
|
||||
|
||||
path = Path(".")
|
||||
|
||||
files = list(path.glob("CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
files = list(path.glob("../CHANGELOG.md"))
|
||||
|
||||
if (len(files) != 1):
|
||||
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
|
||||
exit(1)
|
||||
|
||||
print("Scanning CHANGELOG.md ...")
|
||||
|
||||
changelog_prs = []
|
||||
|
||||
with open(files[0]) as changelog:
|
||||
line = changelog.readline()
|
||||
while (line):
|
||||
#print("line: " + line)
|
||||
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
|
||||
if (match):
|
||||
if match.group(1) == version:
|
||||
#print("found version")
|
||||
line = changelog.readline()
|
||||
continue
|
||||
else:
|
||||
#print("done with " + match.group(1))
|
||||
break
|
||||
|
||||
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
|
||||
if match:
|
||||
changelog_prs.append(match.group(1))
|
||||
|
||||
line = changelog.readline()
|
||||
|
||||
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
|
||||
|
||||
print("")
|
||||
|
||||
copy_array = changelog_prs.copy()
|
||||
print("PRs in CHANGELOG.md that are not in Milestone:")
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] in copy_array:
|
||||
copy_array.remove(pr['number'])
|
||||
for pr in copy_array:
|
||||
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
|
||||
|
||||
print("")
|
||||
|
||||
print("PRs in milestone that are not in CHANGELOG.md:")
|
||||
|
||||
for pr in milestone_prs:
|
||||
if pr['number'] not in changelog_prs:
|
||||
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
|
||||
|
||||
main()
|
@ -59,17 +59,24 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress) {
|
||||
bool hasAdditionalData = false;
|
||||
const uint8_t* dataPtr = nullptr;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
return;
|
||||
ReturnValue_t result;
|
||||
if (dataAddress != store_address_t::invalid()) {
|
||||
hasAdditionalData = true;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
if (result != returnvalue::OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
if (hasAdditionalData) {
|
||||
ipcStore->deleteData(dataAddress);
|
||||
}
|
||||
if (result == HasActionsIF::EXECUTION_FINISHED) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/CfdpHandler.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
|
@ -1,3 +1,2 @@
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp)
|
||||
|
@ -1,134 +0,0 @@
|
||||
#include "CfdpHandler.h"
|
||||
|
||||
#include "fsfw/cfdp/pdu/AckPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
using namespace cfdp;
|
||||
|
||||
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
|
||||
: SystemObject(fsfwParams.objectId),
|
||||
msgQueue(fsfwParams.msgQueue),
|
||||
destHandler(
|
||||
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
|
||||
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
|
||||
cfdpCfg.lostSegmentsList),
|
||||
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
|
||||
fsfwParams.tmStore)) {
|
||||
destHandler.setMsgQueue(msgQueue);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
|
||||
|
||||
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
|
||||
return destHandler.getDestHandlerParams().cfg.localId.getValue();
|
||||
}
|
||||
|
||||
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
|
||||
|
||||
ReturnValue_t CfdpHandler::initialize() {
|
||||
ReturnValue_t result = destHandler.initialize();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
tcStore = destHandler.getTcStore();
|
||||
tmStore = destHandler.getTmStore();
|
||||
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
|
||||
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
|
||||
// correct or more appropriate
|
||||
ReturnValue_t status;
|
||||
ReturnValue_t result = OK;
|
||||
TmTcMessage tmtcMsg;
|
||||
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
|
||||
status = msgQueue.receiveMessage(&tmtcMsg)) {
|
||||
result = handleCfdpPacket(tmtcMsg);
|
||||
if (result != OK) {
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
auto& fsmRes = destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
|
||||
destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
|
||||
auto accessorPair = tcStore->getData(msg.getStorageId());
|
||||
if (accessorPair.first != OK) {
|
||||
return accessorPair.first;
|
||||
}
|
||||
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
// The CFDP distributor should have taken care of ensuring the destination ID is correct
|
||||
PduType type = reader.getPduType();
|
||||
// Only the destination handler can process these PDUs
|
||||
if (type == PduType::FILE_DATA) {
|
||||
// Disable auto-deletion of packet
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId());
|
||||
result = destHandler.passPacket(info);
|
||||
} else {
|
||||
// Route depending on PDU type and directive type if applicable. It retrieves directive type
|
||||
// from the raw stream for better performance (with sanity and directive code check).
|
||||
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||
// procedure.
|
||||
|
||||
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
|
||||
// with at least one byte being the directive code
|
||||
const uint8_t* pduDataField = reader.getPduDataField();
|
||||
if (pduDataField == nullptr) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
|
||||
return INVALID_DIRECTIVE_FIELD;
|
||||
}
|
||||
auto directive = static_cast<FileDirective>(pduDataField[0]);
|
||||
|
||||
auto passToDestHandler = [&]() {
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId(), directive);
|
||||
result = destHandler.passPacket(info);
|
||||
};
|
||||
auto passToSourceHandler = [&]() {
|
||||
|
||||
};
|
||||
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
|
||||
directive == FileDirective::PROMPT) {
|
||||
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||
// the destination handler
|
||||
passToDestHandler();
|
||||
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
|
||||
directive == FileDirective::KEEP_ALIVE) {
|
||||
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||
// the source handler
|
||||
passToSourceHandler();
|
||||
} else if (directive == FileDirective::ACK) {
|
||||
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||
FileDirective ackedDirective;
|
||||
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
|
||||
return INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
|
||||
passToSourceHandler();
|
||||
} else if (ackedDirective == FileDirective::FINISH) {
|
||||
passToDestHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/handler/DestHandler.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
struct FsfwHandlerParams {
|
||||
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
|
||||
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
|
||||
: objectId(objectId),
|
||||
vfs(vfs),
|
||||
packetDest(packetDest),
|
||||
tcStore(tcStore),
|
||||
tmStore(tmStore),
|
||||
msgQueue(msgQueue) {}
|
||||
object_id_t objectId{};
|
||||
HasFileSystemIF& vfs;
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
StorageManagerIF& tcStore;
|
||||
StorageManagerIF& tmStore;
|
||||
MessageQueueIF& msgQueue;
|
||||
};
|
||||
|
||||
struct CfdpHandlerCfg {
|
||||
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
|
||||
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
|
||||
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider)
|
||||
: id(std::move(localId)),
|
||||
indicCfg(indicationCfg),
|
||||
packetInfoList(packetInfo),
|
||||
lostSegmentsList(lostSegmentsList),
|
||||
remoteCfgProvider(remoteCfgProvider),
|
||||
userHandler(userHandler),
|
||||
faultHandler(userFaultHandler) {}
|
||||
|
||||
cfdp::EntityId id;
|
||||
cfdp::IndicationCfg indicCfg;
|
||||
cfdp::PacketInfoListBase& packetInfoList;
|
||||
cfdp::LostSegmentsListBase& lostSegmentsList;
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider;
|
||||
cfdp::UserBase& userHandler;
|
||||
cfdp::FaultHandlerBase& faultHandler;
|
||||
};
|
||||
|
||||
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
|
||||
public:
|
||||
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
|
||||
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
cfdp::DestHandler destHandler;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
|
||||
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
|
||||
};
|
||||
|
||||
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
@ -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
|
||||
|
||||
|
@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
|
||||
*buffer += 1;
|
||||
**buffer = pduDataFieldLen & 0x00ff;
|
||||
*buffer += 1;
|
||||
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
|
||||
pduConf.seqNum.getWidth();
|
||||
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
|
||||
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
|
||||
*buffer += 1;
|
||||
*size += 4;
|
||||
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);
|
||||
|
@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const {
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
|
||||
return static_cast<cfdp::WidthInBytes>(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1);
|
||||
}
|
||||
|
||||
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
|
||||
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
|
||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
|
||||
}
|
||||
|
||||
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
||||
|
@ -58,7 +58,7 @@ void ControllerBase::handleQueue() {
|
||||
|
||||
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||
changeHK(this->mode, this->submode, false);
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
triggerEvent(CHANGING_MODE, mode_, submode_);
|
||||
mode = mode_;
|
||||
submode = submode_;
|
||||
modeHelper.modeChanged(mode, submode);
|
||||
|
@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
|
||||
timeval timeSinceEpoch = time - epoch;
|
||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||
|
||||
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
||||
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30;
|
||||
|
||||
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
||||
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) {
|
||||
return TLE_TOO_OLD;
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
|
||||
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
|
||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
|
||||
return initializeHousekeepingPoolEntriesOnce();
|
||||
}
|
||||
|
||||
@ -506,9 +505,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
||||
float newCollIntvl = 0;
|
||||
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
|
||||
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, true);
|
||||
result = changeCollectionInterval(sid, newCollIntvl);
|
||||
} else {
|
||||
result = changeCollectionInterval(sid, newCollIntvl, false);
|
||||
result = changeCollectionInterval(sid, newCollIntvl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -661,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
|
||||
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
||||
}
|
||||
|
||||
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
|
||||
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
|
||||
}
|
||||
|
||||
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||
sid_t sid = receiver.dataId.sid;
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
@ -718,15 +713,15 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
|
||||
|
||||
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
|
||||
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
||||
return REPORTING_STATUS_UNCHANGED;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||
bool isDiagnostics) {
|
||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
||||
float newCollectionInterval) {
|
||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||
if (dataSet == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
|
||||
@ -734,11 +729,6 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float ne
|
||||
return DATASET_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
||||
if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) {
|
||||
return WRONG_HK_PACKET_TYPE;
|
||||
}
|
||||
|
||||
PeriodicHousekeepingHelper* periodicHelper =
|
||||
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
||||
|
||||
|
@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
* @param nonDiagInvlFactor
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
|
||||
ReturnValue_t initializeAfterTaskCreation();
|
||||
|
||||
/**
|
||||
* @brief This should be called in the periodic handler of the owner.
|
||||
@ -152,17 +152,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
MessageQueueId_t targetQueueId,
|
||||
bool generateSnapshot) override;
|
||||
|
||||
/**
|
||||
* Non-Diagnostics packets usually have a lower minimum sampling frequency
|
||||
* than diagnostic packets.
|
||||
* A factor can be specified to determine the minimum sampling frequency
|
||||
* for non-diagnostic packets. The minimum sampling frequency of the
|
||||
* diagnostics packets,which is usually jusst the period of the
|
||||
* performOperation calls, is multiplied with that factor.
|
||||
* @param factor
|
||||
*/
|
||||
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
|
||||
|
||||
/**
|
||||
* @brief The manager is also able to handle housekeeping messages.
|
||||
* @details
|
||||
@ -185,6 +174,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet,
|
||||
bool forDownlink,
|
||||
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
|
||||
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval);
|
||||
|
||||
HasLocalDataPoolIF* getOwner();
|
||||
|
||||
@ -348,8 +338,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
||||
|
||||
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
|
||||
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
|
||||
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||
bool isDiagnostics);
|
||||
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
|
||||
|
||||
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
|
||||
|
@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
|
||||
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
||||
|
||||
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
||||
dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor) {
|
||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
|
||||
dur_millis_t minimumPeriodicInterval) {
|
||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
|
||||
}
|
||||
|
||||
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
||||
|
@ -191,8 +191,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor = 5);
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||
|
||||
/**
|
||||
* If the valid state of a dataset is always relevant to the whole
|
||||
|
@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney {
|
||||
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
||||
|
||||
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
||||
uint32_t minimumPeriodicIntervalMs,
|
||||
uint8_t nonDiagIntervalFactor = 5) {
|
||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
|
||||
nonDiagIntervalFactor);
|
||||
uint32_t minimumPeriodicIntervalMs) {
|
||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
|
||||
}
|
||||
|
||||
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
||||
|
@ -49,6 +49,7 @@ class DeviceCommunicationIF {
|
||||
// is this needed if there is no open/close call?
|
||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
||||
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
|
||||
|
||||
virtual ~DeviceCommunicationIF() {}
|
||||
|
||||
|
@ -58,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) {
|
||||
@ -227,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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,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:
|
||||
@ -395,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);
|
||||
@ -574,6 +565,9 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
*/
|
||||
if (newMode == MODE_ON and continueToNormal) {
|
||||
continueToNormal = false;
|
||||
// TODO: Check whether the following two lines are okay to do so.
|
||||
transitionSourceMode = MODE_ON;
|
||||
transitionSourceSubMode = newSubmode;
|
||||
mode = _MODE_TO_NORMAL;
|
||||
return;
|
||||
}
|
||||
@ -594,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 */
|
||||
@ -1088,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);
|
||||
@ -1150,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1477,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;
|
||||
}
|
||||
@ -1494,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());
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include "DeviceCommunicationIF.h"
|
||||
#include "DeviceHandlerFailureIsolation.h"
|
||||
@ -149,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);
|
||||
|
||||
@ -163,13 +159,8 @@ 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;
|
||||
@ -266,8 +257,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
Mode_t getTransitionSourceMode() const;
|
||||
Submode_t getTransitionSourceSubMode() const;
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
||||
HealthState getHealth();
|
||||
ReturnValue_t setHealth(HealthState health);
|
||||
virtual HealthState getHealth() override;
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
const ParameterWrapper *newValues,
|
||||
@ -931,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.
|
||||
*
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent)
|
||||
: FailureIsolationBase(owner, parent),
|
||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth)
|
||||
: FailureIsolationBase(owner, parent, eventQueueDepth),
|
||||
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS,
|
||||
parameterDomainBase++),
|
||||
missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS,
|
||||
|
@ -13,7 +13,8 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
|
||||
friend class Heater;
|
||||
|
||||
public:
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent);
|
||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
||||
uint8_t eventQueueDepth = 10);
|
||||
~DeviceHandlerFailureIsolation();
|
||||
ReturnValue_t initialize();
|
||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
||||
|
@ -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_ */
|
||||
|
@ -29,11 +29,10 @@ ReturnValue_t HealthDevice::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (parentQueue != 0) {
|
||||
if (parentQueue != MessageQueueIF::NO_QUEUE) {
|
||||
return healthHelper.initialize(parentQueue);
|
||||
} else {
|
||||
return healthHelper.initialize();
|
||||
}
|
||||
return healthHelper.initialize();
|
||||
}
|
||||
|
||||
MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); }
|
||||
|
@ -29,10 +29,8 @@ class HealthDevice : public SystemObject, public ExecutableObjectIF, public HasH
|
||||
protected:
|
||||
HealthState lastHealth;
|
||||
|
||||
MessageQueueId_t parentQueue;
|
||||
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueIF* commandQueue;
|
||||
|
||||
public:
|
||||
HealthHelper healthHelper;
|
||||
};
|
||||
|
||||
|
@ -15,12 +15,12 @@ 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() {
|
||||
@ -55,8 +55,9 @@ void EventManager::notifyListeners(EventMessage* message) {
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||
<< result << std::setfill(' ') << std::endl;
|
||||
<< std::setw(8) << listener.first << " for event 0x" << std::setw(4)
|
||||
<< message->getEventId() << " failed with result 0x" << std::setw(4) << result
|
||||
<< std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||
listener.first, result);
|
||||
|
@ -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);
|
||||
|
@ -10,7 +10,7 @@ enum : uint8_t {
|
||||
CDH = 28,
|
||||
TCS_1 = 59,
|
||||
PCDU_1 = 42,
|
||||
PCDU_2 = 43,
|
||||
POWER_SWITCH_IF = 43,
|
||||
HEATER = 50,
|
||||
T_SENSORS = 52,
|
||||
FDIR = 70,
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -18,8 +18,11 @@
|
||||
*/
|
||||
class DleParser {
|
||||
public:
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
|
||||
//! [EXPORT] : [SKIP]
|
||||
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
|
||||
|
||||
using BufPair = std::pair<uint8_t*, size_t>;
|
||||
|
||||
enum class ContextType { NONE, PACKET_FOUND, ERROR };
|
||||
|
@ -53,8 +53,9 @@ class VectorOperations {
|
||||
mulScalar(vector, 1 / norm(vector, size), normalizedVector, size);
|
||||
}
|
||||
|
||||
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||
T max = -1;
|
||||
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
||||
T max = vector[size - 1];
|
||||
uint8_t foundIndex = size - 1;
|
||||
|
||||
for (; size > 0; size--) {
|
||||
T abs = vector[size - 1];
|
||||
@ -64,24 +65,35 @@ class VectorOperations {
|
||||
if (abs > max) {
|
||||
max = abs;
|
||||
if (index != 0) {
|
||||
*index = size - 1;
|
||||
foundIndex = size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index != nullptr) {
|
||||
*index = foundIndex;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
static T maxValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||
T max = -1;
|
||||
static T maxValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
||||
T max = vector[size - 1];
|
||||
uint8_t foundIndex = size - 1;
|
||||
|
||||
for (; size > 0; size--) {
|
||||
if (vector[size - 1] > max) {
|
||||
max = vector[size - 1];
|
||||
if (index != 0) {
|
||||
*index = size - 1;
|
||||
foundIndex = size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index != nullptr) {
|
||||
*index = foundIndex;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
@ -3,85 +3,37 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "fsfw/datapoollocal/LocalPoolDataSetBase.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner)
|
||||
: owner(owner) {}
|
||||
|
||||
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
||||
dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor) {
|
||||
dur_millis_t minimumPeriodicInterval) {
|
||||
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
||||
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
|
||||
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
||||
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
|
||||
if a HK packet is generated immediately instead of waiting one generation cycle. */
|
||||
internalTickCounter = collectionIntervalTicks;
|
||||
changeCollectionInterval(collectionInterval);
|
||||
}
|
||||
|
||||
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
|
||||
return intervalTicksToSeconds(collectionIntervalTicks);
|
||||
return collectionInterval;
|
||||
}
|
||||
|
||||
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
||||
if (internalTickCounter >= collectionIntervalTicks) {
|
||||
internalTickCounter = 1;
|
||||
if (hkGenerationCd.hasTimedOut()) {
|
||||
hkGenerationCd.resetTimer();
|
||||
return true;
|
||||
}
|
||||
internalTickCounter++;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
|
||||
float collectionIntervalSeconds) {
|
||||
if (owner == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
bool isDiagnostics = owner->isDiagnostics();
|
||||
|
||||
/* Avoid division by zero */
|
||||
if (minimumPeriodicInterval == 0) {
|
||||
if (isDiagnostics) {
|
||||
/* Perform operation each cycle */
|
||||
return 1;
|
||||
} else {
|
||||
return nonDiagIntervalFactor;
|
||||
}
|
||||
} else {
|
||||
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
||||
uint32_t divisor = minimumPeriodicInterval;
|
||||
if (not isDiagnostics) {
|
||||
/* We need to multiply the divisor because non-diagnostics only
|
||||
allow a multiple of the minimum periodic interval */
|
||||
divisor *= nonDiagIntervalFactor;
|
||||
}
|
||||
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
|
||||
if (not isDiagnostics) {
|
||||
/* Now we need to multiply the calculated ticks with the factor as as well
|
||||
because the minimum tick count to generate a non-diagnostic is the factor itself.
|
||||
|
||||
Example calculation for non-diagnostic with
|
||||
0.4 second interval and 0.2 second task interval.
|
||||
Resultant tick count of 5 is equal to operation each second.
|
||||
|
||||
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
|
||||
task interval.
|
||||
Resultant tick count of 10 is equal to operatin every 2 seconds.
|
||||
|
||||
Example calculation for diagnostic with 0.4 second interval and 0.3
|
||||
second task interval. Resulting tick count of 2 is equal to operation
|
||||
every 0.6 seconds. */
|
||||
ticks *= nonDiagIntervalFactor;
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
}
|
||||
|
||||
float PeriodicHousekeepingHelper::intervalTicksToSeconds(uint32_t collectionInterval) const {
|
||||
/* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
|
||||
the value in seconds */
|
||||
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
|
||||
}
|
||||
|
||||
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
|
||||
collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
|
||||
uint32_t intervalMs = newIntervalSeconds * 1000;
|
||||
if (newIntervalSeconds <= 0) {
|
||||
intervalMs = minimumPeriodicInterval;
|
||||
newIntervalSeconds = static_cast<float>(minimumPeriodicInterval) / 1000.0;
|
||||
}
|
||||
collectionInterval = newIntervalSeconds;
|
||||
hkGenerationCd.setTimeout(intervalMs);
|
||||
// We want an immediate HK packet at the start, so time out the generation CD immediately.
|
||||
hkGenerationCd.timeOut();
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "fsfw/timemanager/Clock.h"
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
class LocalPoolDataSetBase;
|
||||
|
||||
@ -11,8 +12,7 @@ class PeriodicHousekeepingHelper {
|
||||
public:
|
||||
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
||||
|
||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor);
|
||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||
|
||||
void changeCollectionInterval(float newInterval);
|
||||
float getCollectionIntervalInSeconds() const;
|
||||
@ -20,14 +20,10 @@ class PeriodicHousekeepingHelper {
|
||||
|
||||
private:
|
||||
LocalPoolDataSetBase* owner = nullptr;
|
||||
uint8_t nonDiagIntervalFactor = 0;
|
||||
|
||||
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
||||
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
||||
Countdown hkGenerationCd;
|
||||
float collectionInterval = 0.0;
|
||||
|
||||
dur_millis_t minimumPeriodicInterval = 0;
|
||||
uint32_t internalTickCounter = 1;
|
||||
uint32_t collectionIntervalTicks = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */
|
||||
|
@ -5,9 +5,12 @@
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
||||
bool enableSetByDefault, float generationFrequency)
|
||||
: SystemObject(setObjectId),
|
||||
poolManager(this, commandQueue),
|
||||
enableSetByDefault(enableSetByDefault),
|
||||
generationFrequency(generationFrequency),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
@ -134,9 +137,8 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool
|
||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
|
||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
|
||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
|
||||
poolManager.subscribeForDiagPeriodicPacket(subdp::DiagnosticsHkPeriodicParams(
|
||||
internalErrorSid, false,
|
||||
static_cast<float>(getPeriodicOperationFrequency()) / static_cast<float>(1000.0)));
|
||||
poolManager.subscribeForRegularPeriodicPacket(
|
||||
subdp::RegularHkPeriodicParams(internalErrorSid, enableSetByDefault, generationFrequency));
|
||||
internalErrorDataset.setValidity(true, true);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ class InternalErrorReporter : public SystemObject,
|
||||
public InternalErrorReporterIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5);
|
||||
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
||||
bool enableSetByDefault, float generationFrequency);
|
||||
|
||||
/**
|
||||
* Enable diagnostic printout. Please note that this feature will
|
||||
@ -63,6 +64,8 @@ class InternalErrorReporter : public SystemObject,
|
||||
MutexIF* mutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
bool enableSetByDefault;
|
||||
float generationFrequency;
|
||||
|
||||
sid_t internalErrorSid;
|
||||
InternalErrorDataset internalErrorDataset;
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -20,16 +20,18 @@ TaskFactory::~TaskFactory() = default;
|
||||
|
||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||
|
||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||
TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_,
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||
void* args) {
|
||||
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||
deadLineMissedFunction_);
|
||||
}
|
||||
|
||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
|
||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||
deadLineMissedFunction_);
|
||||
}
|
||||
|
@ -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);
|
||||
@ -76,14 +89,17 @@ timeval Clock::getUptime() {
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -7,10 +7,15 @@
|
||||
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN;
|
||||
|
||||
FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_)
|
||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
|
||||
PosixThreadArgs* args)
|
||||
: FixedTimeslotTaskBase(periodSeconds_, dlmFunc_),
|
||||
posixThread(name_, priority_, stackSize_),
|
||||
started(false) {}
|
||||
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
|
||||
started(false) {
|
||||
if (args != nullptr) {
|
||||
posixThread.setSchedPolicy(args->policy);
|
||||
}
|
||||
}
|
||||
|
||||
void* FixedTimeslotTask::taskEntryPoint(void* arg) {
|
||||
// The argument is re-interpreted as PollingTask.
|
||||
|
@ -23,7 +23,8 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase {
|
||||
* @param deadlineMissedFunc_
|
||||
*/
|
||||
FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_,
|
||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_);
|
||||
TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_,
|
||||
PosixThreadArgs* args);
|
||||
~FixedTimeslotTask() override = default;
|
||||
|
||||
ReturnValue_t startTask() override;
|
||||
|
@ -4,10 +4,15 @@
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
|
||||
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_,
|
||||
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_)
|
||||
TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_,
|
||||
PosixThreadArgs* args)
|
||||
: PeriodicTaskBase(period_, dlmFunc_),
|
||||
posixThread(name_, priority_, stackSize_),
|
||||
started(false) {}
|
||||
posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_),
|
||||
started(false) {
|
||||
if (args != nullptr) {
|
||||
posixThread.setSchedPolicy(args->policy);
|
||||
}
|
||||
}
|
||||
|
||||
void* PeriodicPosixTask::taskEntryPoint(void* arg) {
|
||||
// The argument is re-interpreted as PollingTask.
|
||||
|
@ -24,7 +24,7 @@ class PeriodicPosixTask : public PeriodicTaskBase {
|
||||
* @param deadlineMissedFunc_
|
||||
*/
|
||||
PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_,
|
||||
TaskDeadlineMissedFunction dlmFunc_);
|
||||
TaskDeadlineMissedFunction dlmFunc_, PosixThreadArgs* args);
|
||||
~PeriodicPosixTask() override = default;
|
||||
|
||||
/**
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include "fsfw/osal/linux/unixUtility.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_)
|
||||
: thread(0), priority(priority_), stackSize(stackSize_) {
|
||||
PosixThread::PosixThread(const char* name_, SchedulingPolicy schedPolciy, int priority_,
|
||||
size_t stackSize_)
|
||||
: thread(0), schedPolicy(schedPolciy), priority(priority_), stackSize(stackSize_) {
|
||||
name[0] = '\0';
|
||||
std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1);
|
||||
}
|
||||
@ -178,20 +179,30 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
||||
#ifndef FSFW_USE_REALTIME_FOR_LINUX
|
||||
#error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1"
|
||||
#endif
|
||||
if (schedPolicy == SchedulingPolicy::RR) {
|
||||
// RR -> This needs root privileges for the process
|
||||
#if FSFW_USE_REALTIME_FOR_LINUX == 1
|
||||
// FIFO -> This needs root privileges for the process
|
||||
status = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO);
|
||||
if (status != 0) {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
|
||||
status = pthread_attr_setschedpolicy(&attributes, SCHED_RR);
|
||||
if (status != 0) {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy");
|
||||
}
|
||||
sched_param scheduleParams;
|
||||
scheduleParams.sched_priority = priority;
|
||||
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
|
||||
if (status != 0) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "PosixThread: Setting priority failed" << std::endl;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning
|
||||
<< "Real time priorities are only allowed if FSFW_USE_REALTIME_FOR_LINUX is set to 1"
|
||||
<< std::endl;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
sched_param scheduleParams;
|
||||
scheduleParams.__sched_priority = priority;
|
||||
status = pthread_attr_setschedparam(&attributes, &scheduleParams);
|
||||
if (status != 0) {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam");
|
||||
}
|
||||
#endif
|
||||
// Set Signal Mask for suspend until startTask is called
|
||||
sigset_t waitSignal;
|
||||
sigemptyset(&waitSignal);
|
||||
@ -243,3 +254,5 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) {
|
||||
utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy");
|
||||
}
|
||||
}
|
||||
|
||||
void PosixThread::setSchedPolicy(SchedulingPolicy policy) { this->schedPolicy = policy; }
|
||||
|
@ -9,10 +9,15 @@
|
||||
|
||||
#include "../../returnvalues/returnvalue.h"
|
||||
|
||||
enum SchedulingPolicy { REGULAR, RR };
|
||||
struct PosixThreadArgs {
|
||||
SchedulingPolicy policy = SchedulingPolicy::REGULAR;
|
||||
};
|
||||
|
||||
class PosixThread {
|
||||
public:
|
||||
static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16;
|
||||
PosixThread(const char* name_, int priority_, size_t stackSize_);
|
||||
PosixThread(const char* name_, SchedulingPolicy schedPolicy, int priority_, size_t stackSize_);
|
||||
virtual ~PosixThread();
|
||||
/**
|
||||
* Set the Thread to sleep state
|
||||
@ -20,6 +25,9 @@ class PosixThread {
|
||||
* @return Returns Failed if sleep fails
|
||||
*/
|
||||
static ReturnValue_t sleep(uint64_t ns);
|
||||
|
||||
void setSchedPolicy(SchedulingPolicy policy);
|
||||
|
||||
/**
|
||||
* @brief Function to suspend the task until SIGUSR1 was received
|
||||
*
|
||||
@ -72,6 +80,7 @@ class PosixThread {
|
||||
|
||||
private:
|
||||
char name[PTHREAD_MAX_NAMELEN];
|
||||
SchedulingPolicy schedPolicy;
|
||||
int priority;
|
||||
size_t stackSize = 0;
|
||||
|
||||
|
@ -12,18 +12,20 @@ TaskFactory::~TaskFactory() = default;
|
||||
|
||||
TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; }
|
||||
|
||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(
|
||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||
TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_,
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||
void* args) {
|
||||
return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||
deadLineMissedFunction_);
|
||||
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
|
||||
}
|
||||
|
||||
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(
|
||||
TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) {
|
||||
TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) {
|
||||
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_,
|
||||
deadLineMissedFunction_);
|
||||
deadLineMissedFunction_, reinterpret_cast<PosixThreadArgs*>(args));
|
||||
}
|
||||
|
||||
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "fsfw/osal/rtems/BinarySemaphore.h"
|
||||
//#include "fsfw/osal/rtems/CountingSemaphore.h"
|
||||
// #include "fsfw/osal/rtems/CountingSemaphore.h"
|
||||
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/tasks/SemaphoreFactory.h"
|
||||
|
@ -6,7 +6,11 @@ DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwit
|
||||
: SystemObject(objectId, registerGlobally),
|
||||
switcherList(numberOfSwitches),
|
||||
fuseList(numberOfFuses),
|
||||
switchDelayMs(switchDelayMs) {}
|
||||
switchDelayMs(switchDelayMs) {
|
||||
for (auto &switchState : switcherList) {
|
||||
switchState = PowerSwitchIF::SWITCH_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
void DummyPowerSwitcher::setInitialSwitcherList(std::vector<ReturnValue_t> switcherList) {
|
||||
this->switcherList = switcherList;
|
||||
|
@ -32,7 +32,7 @@ class Fuse : public SystemObject,
|
||||
gp_id_t poolIdPower;
|
||||
};
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
|
||||
//! PSS detected that current on a fuse is totally out of bounds.
|
||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
||||
//! PSS detected a fuse that went off.
|
||||
|
@ -28,7 +28,9 @@ class PowerSwitchIF {
|
||||
static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2);
|
||||
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
|
||||
static const ReturnValue_t SWITCH_UNKNOWN = MAKE_RETURN_CODE(5);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::POWER_SWITCH_IF;
|
||||
//!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||
@ -50,6 +52,7 @@ class PowerSwitchIF {
|
||||
* @return
|
||||
* - @c SWITCH_ON if the specified switch is on.
|
||||
* - @c SWITCH_OFF if the specified switch is off.
|
||||
* - @c SWITCH_UNKNOWN if the state of the specified switch is unknown.
|
||||
* - @c returnvalue::FAILED if an error occured
|
||||
*/
|
||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/power/PowerSwitchIF.h>
|
||||
#include <fsfw/subsystem/helper.h>
|
||||
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||
power::Switch_t pwrSwitch)
|
||||
@ -28,6 +29,9 @@ ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (getHealth() == FAULTY) {
|
||||
performFaultyOperation();
|
||||
}
|
||||
if (switcher.active()) {
|
||||
switcher.doStateMachine();
|
||||
auto currState = switcher.getState();
|
||||
@ -111,9 +115,11 @@ const HasHealthIF* PowerSwitcherComponent::getOptHealthIF() const { return this;
|
||||
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return parent.registerChild(*this);
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
|
||||
|
||||
void PowerSwitcherComponent::performFaultyOperation() {}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
||||
#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_
|
||||
#pragma once
|
||||
|
||||
#include <fsfw/health/HasHealthIF.h>
|
||||
#include <fsfw/health/HealthHelper.h>
|
||||
@ -37,11 +36,13 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
private:
|
||||
MessageQueueIF *queue = nullptr;
|
||||
protected:
|
||||
PowerSwitcher switcher;
|
||||
|
||||
Mode_t mode = MODE_OFF;
|
||||
private:
|
||||
MessageQueueIF *queue = nullptr;
|
||||
|
||||
Mode_t mode = MODE_UNDEFINED;
|
||||
Submode_t submode = 0;
|
||||
|
||||
ModeHelper modeHelper;
|
||||
@ -49,24 +50,23 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
|
||||
void setMode(Mode_t newMode, Submode_t newSubmode);
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
MessageQueueId_t getCommandQueue() const override;
|
||||
[[nodiscard]] MessageQueueId_t getCommandQueue() const override;
|
||||
void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override;
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
virtual void performFaultyOperation();
|
||||
void setToExternalControl() override;
|
||||
void announceMode(bool recursive) override;
|
||||
|
||||
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;
|
||||
[[nodiscard]] object_id_t getObjectId() const override;
|
||||
[[nodiscard]] const HasHealthIF *getOptHealthIF() const override;
|
||||
[[nodiscard]] const HasModesIF &getModeIF() const override;
|
||||
};
|
||||
|
||||
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */
|
||||
|
@ -19,7 +19,7 @@ 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:
|
||||
@ -54,6 +54,7 @@ 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) {
|
||||
bool recursive = false;
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_MODE_COMMAND): {
|
||||
ModePacket modeCommandPacket;
|
||||
@ -67,22 +68,17 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message,
|
||||
modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
case (Subservice::COMMAND_MODE_ANNCOUNCE):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY): {
|
||||
bool recursive = true;
|
||||
if (subservice == Subservice::COMMAND_MODE_ANNCOUNCE) {
|
||||
recursive = false;
|
||||
}
|
||||
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): {
|
||||
case (Subservice::COMMAND_MODE_READ):
|
||||
ModeMessage::setModeReadMessage(*message);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
default: {
|
||||
default:
|
||||
return CommandingServiceBase::INVALID_SUBSERVICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -10,9 +10,23 @@
|
||||
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
||||
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
||||
args.numParallelCommands, args.commandTimeoutSeconds),
|
||||
healthTable(args.table),
|
||||
healthTableId(args.table),
|
||||
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::initialize() {
|
||||
ReturnValue_t result = CommandingServiceBase::initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
healthTable = ObjectManager::instance()->get<HealthTable>(healthTableId);
|
||||
if (healthTable == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
|
||||
switch (subservice) {
|
||||
case (Subservice::COMMAND_SET_HEALTH):
|
||||
@ -68,6 +82,9 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
||||
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) {
|
||||
@ -79,7 +96,7 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||
break;
|
||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||
}
|
||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||
ReturnValue_t result = iterateHealthTable(true);
|
||||
@ -88,14 +105,6 @@ ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message,
|
||||
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
|
||||
@ -142,7 +151,7 @@ void CServiceHealthCommanding::doPeriodicOperation() {
|
||||
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
||||
std::pair<object_id_t, HasHealthIF::HealthState> pair;
|
||||
|
||||
ReturnValue_t result = healthTable.iterate(&pair, reset);
|
||||
ReturnValue_t result = healthTable->iterate(&pair, reset);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
} else {
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||
|
||||
struct HealthServiceCfg {
|
||||
HealthServiceCfg(object_id_t objectId, uint16_t apid, HealthTable &healthTable,
|
||||
HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable,
|
||||
uint16_t maxNumHealthInfoPerCycle)
|
||||
: objectId(objectId),
|
||||
apid(apid),
|
||||
@ -14,7 +14,7 @@ struct HealthServiceCfg {
|
||||
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
||||
object_id_t objectId;
|
||||
uint16_t apid;
|
||||
HealthTable &table;
|
||||
object_id_t table;
|
||||
uint16_t maxNumHealthInfoPerCycle;
|
||||
uint8_t service = 201;
|
||||
uint8_t numParallelCommands = 4;
|
||||
@ -40,6 +40,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
|
||||
CServiceHealthCommanding(HealthServiceCfg args);
|
||||
~CServiceHealthCommanding() override = default;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
protected:
|
||||
/* CSB abstract function implementations */
|
||||
ReturnValue_t isValidSubservice(uint8_t subservice) override;
|
||||
@ -57,7 +59,8 @@ class CServiceHealthCommanding : public CommandingServiceBase {
|
||||
void doPeriodicOperation() override;
|
||||
|
||||
private:
|
||||
HealthTable &healthTable;
|
||||
const object_id_t healthTableId;
|
||||
HealthTable *healthTable;
|
||||
uint16_t maxNumHealthInfoPerCycle = 0;
|
||||
bool reportAllHealth = false;
|
||||
ReturnValue_t iterateHealthTable(bool reset);
|
||||
|
@ -160,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"
|
||||
|
@ -4,9 +4,10 @@
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/pus/servicepackets/Service3Packets.h"
|
||||
|
||||
Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId)
|
||||
: CommandingServiceBase(objectId, apid, "PUS 3 HK", serviceId, NUM_OF_PARALLEL_COMMANDS,
|
||||
COMMAND_TIMEOUT_SECONDS) {}
|
||||
Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||
uint32_t queueDepth, uint8_t numParallelCommands)
|
||||
: CommandingServiceBase(objectId, apid, "PUS 3 HK", serviceId, numParallelCommands,
|
||||
COMMAND_TIMEOUT_SECONDS, queueDepth) {}
|
||||
|
||||
Service3Housekeeping::~Service3Housekeeping() {}
|
||||
|
||||
|
@ -28,7 +28,8 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke
|
||||
static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4;
|
||||
static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60;
|
||||
|
||||
Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId);
|
||||
Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint32_t queueDepth,
|
||||
uint8_t numParallelCommands);
|
||||
virtual ~Service3Housekeeping();
|
||||
|
||||
protected:
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
Service8FunctionManagement::Service8FunctionManagement(object_id_t objectId, uint16_t apid,
|
||||
uint8_t serviceId,
|
||||
uint8_t serviceId, size_t queueDepth,
|
||||
uint8_t numParallelCommands,
|
||||
uint16_t commandTimeoutSeconds)
|
||||
: CommandingServiceBase(objectId, apid, "PUS 8 Functional Commanding", serviceId,
|
||||
numParallelCommands, commandTimeoutSeconds) {}
|
||||
numParallelCommands, commandTimeoutSeconds, queueDepth) {}
|
||||
|
||||
Service8FunctionManagement::~Service8FunctionManagement() {}
|
||||
|
||||
|
@ -31,7 +31,8 @@
|
||||
class Service8FunctionManagement : public CommandingServiceBase {
|
||||
public:
|
||||
Service8FunctionManagement(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
||||
size_t queueDepth, uint8_t numParallelCommands = 4,
|
||||
uint16_t commandTimeoutSeconds = 60);
|
||||
~Service8FunctionManagement() override;
|
||||
|
||||
protected:
|
||||
|
@ -10,11 +10,11 @@
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// RMAP command bits
|
||||
//#define RMAP_COMMAND_BIT_INCREMENT 2
|
||||
//#define RMAP_COMMAND_BIT_REPLY 3
|
||||
//#define RMAP_COMMAND_BIT_WRITE 5
|
||||
//#define RMAP_COMMAND_BIT_VERIFY 4
|
||||
//#define RMAP_COMMAND_BIT 6
|
||||
// #define RMAP_COMMAND_BIT_INCREMENT 2
|
||||
// #define RMAP_COMMAND_BIT_REPLY 3
|
||||
// #define RMAP_COMMAND_BIT_WRITE 5
|
||||
// #define RMAP_COMMAND_BIT_VERIFY 4
|
||||
// #define RMAP_COMMAND_BIT 6
|
||||
|
||||
namespace RMAPIds {
|
||||
|
||||
@ -32,14 +32,14 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C
|
||||
static const uint8_t RMAP_REPLY_WRITE =
|
||||
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
|
||||
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
|
||||
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
|
||||
// #define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
|
||||
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
|
||||
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
|
||||
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
||||
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
||||
|
||||
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||
// #define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||
//(1<<RMAP_COMMAND_BIT_REPLY))
|
||||
//#define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||
// #define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||
//(1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define RMAP_REPLY_READ
|
||||
//((1<<RMAP_COMMAND_BIT_REPLY))
|
||||
|
||||
@ -49,9 +49,9 @@ static const uint8_t RMAP_COMMAND_HEADER_LEN = 16;
|
||||
static const uint8_t RMAP_WRITE_REPLY_HEADER_LEN = 8;
|
||||
static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12;
|
||||
static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC
|
||||
//#define RMAP_COMMAND_HEADER_LEN 16
|
||||
//#define RMAP_WRITE_REPLY_HEADER_LEN 8
|
||||
//#define RMAP_READ_REPLY_HEADER_LEN 12
|
||||
// #define RMAP_COMMAND_HEADER_LEN 16
|
||||
// #define RMAP_WRITE_REPLY_HEADER_LEN 8
|
||||
// #define RMAP_READ_REPLY_HEADER_LEN 12
|
||||
|
||||
} // namespace RMAPIds
|
||||
|
||||
|
@ -3,14 +3,14 @@
|
||||
#include "fsfw/FSFW.h"
|
||||
|
||||
PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig)
|
||||
: LocalPool(setObjectId, localPoolConfig, true) {
|
||||
: LocalPool(setObjectId, localPoolConfig, true, true) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
|
||||
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
|
||||
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX);
|
||||
ReturnValue_t status = LocalPool::reserveSpace(size, address);
|
||||
return status;
|
||||
}
|
||||
@ -22,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,6 +56,7 @@ 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) override;
|
||||
|
||||
|
@ -21,6 +21,7 @@ SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(c
|
||||
|
||||
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) {
|
||||
@ -34,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;
|
||||
@ -117,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) {
|
||||
@ -292,20 +315,7 @@ object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectI
|
||||
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;
|
||||
return registerChild(child.getObjectId(), child.getModeIF().getCommandQueue());
|
||||
}
|
||||
|
||||
const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; }
|
||||
@ -313,3 +323,19 @@ const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; }
|
||||
const HasModesIF& SubsystemBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& SubsystemBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t SubsystemBase::registerChild(object_id_t childObjectId, MessageQueueId_t childQueue) {
|
||||
ChildInfo info;
|
||||
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = childQueue;
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
info.submode = SUBMODE_NONE;
|
||||
info.healthChanged = false;
|
||||
|
||||
auto resultPair = childrenMap.emplace(childObjectId, info);
|
||||
if (not resultPair.second) {
|
||||
return COULD_NOT_INSERT_CHILD;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ class SubsystemBase : public SystemObject,
|
||||
* COULD_NOT_INSERT_CHILD If the Child could not be added to the ChildrenMap
|
||||
*/
|
||||
ReturnValue_t registerChild(const ModeTreeChildIF &child) override;
|
||||
// TODO: Add this to HasModeTreeChildrenIF.
|
||||
ReturnValue_t registerChild(object_id_t childObjectId, MessageQueueId_t childQueue);
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -115,6 +117,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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ class TaskFactory {
|
||||
*/
|
||||
PeriodicTaskIF* createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
|
||||
TaskStackSize stackSize_, TaskPeriod periodInSeconds_,
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_);
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||
void* args = nullptr);
|
||||
|
||||
/**
|
||||
* The meaning for the variables for fixed timeslot tasks is the same as for periodic tasks.
|
||||
@ -62,7 +63,8 @@ class TaskFactory {
|
||||
FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, TaskPriority taskPriority_,
|
||||
TaskStackSize stackSize_,
|
||||
TaskPeriod periodInSeconds_,
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_);
|
||||
TaskDeadlineMissedFunction deadLineMissedFunction_,
|
||||
void* args = nullptr);
|
||||
|
||||
/**
|
||||
* Function to be called to delete a task
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -6,47 +6,12 @@
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "tmStorageConf.h"
|
||||
|
||||
class TmPacketMinimal;
|
||||
class SpacePacketBase;
|
||||
class PusTmReader;
|
||||
class SpacePacketReader;
|
||||
class TmStoreBackendIF;
|
||||
|
||||
class TmStoreFrontendIF {
|
||||
public:
|
||||
virtual TmStoreBackendIF* getBackend() const = 0;
|
||||
|
||||
/**
|
||||
* What do I need to implement here?
|
||||
* This is propably used by PUS Service 15 so we should propably check for messages..
|
||||
* Provide base implementation?
|
||||
* @param opCode
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) = 0;
|
||||
/**
|
||||
* Callback from the back-end to indicate a certain packet was received.
|
||||
* front-end takes care of discarding/downloading the packet.
|
||||
* @param packet Pointer to the newly received Space Packet.
|
||||
* @param address Start address of the packet found
|
||||
* @param isLastPacket Indicates if no more packets can be fetched.
|
||||
* @return If more packets shall be fetched, returnvalue::OK must be returned.
|
||||
* Any other code stops fetching packets.
|
||||
*/
|
||||
virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address) = 0;
|
||||
virtual void noMorePacketsInStore() = 0;
|
||||
virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0,
|
||||
uint32_t parameter2 = 0) = 0;
|
||||
/**
|
||||
* To get the queue where commands shall be sent.
|
||||
* @return Id of command queue.
|
||||
*/
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0;
|
||||
virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0;
|
||||
virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0;
|
||||
virtual bool isEnabled() const = 0;
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
virtual void resetDownlinkedPacketCount() = 0;
|
||||
virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0;
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF;
|
||||
static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2);
|
||||
@ -57,7 +22,38 @@ class TmStoreFrontendIF {
|
||||
static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7);
|
||||
static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8);
|
||||
static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9);
|
||||
virtual ~TmStoreFrontendIF() {}
|
||||
|
||||
virtual ~TmStoreFrontendIF() = default;
|
||||
|
||||
/**
|
||||
* To get the queue where commands shall be sent.
|
||||
* @return Id of command queue.
|
||||
*/
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
||||
virtual TmStoreBackendIF* getBackend() const = 0;
|
||||
|
||||
/**
|
||||
* Callback from the back-end to indicate a certain packet was received.
|
||||
* front-end takes care of discarding/downloading the packet.
|
||||
* @param packet Pointer to the newly received Space Packet.
|
||||
* @param address Start address of the packet found
|
||||
* @param isLastPacket Indicates if no more packets can be fetched.
|
||||
* @return If more packets shall be fetched, returnvalue::OK must be returned.
|
||||
* Any other code stops fetching packets.
|
||||
*/
|
||||
virtual ReturnValue_t packetRetrieved(PusTmReader* packet, uint32_t address) = 0;
|
||||
virtual void noMorePacketsInStore() = 0;
|
||||
virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0,
|
||||
uint32_t parameter2 = 0) = 0;
|
||||
|
||||
virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0;
|
||||
virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0;
|
||||
virtual ReturnValue_t checkPacket(SpacePacketReader* tmPacket) = 0;
|
||||
virtual bool isEnabled() const = 0;
|
||||
virtual void setEnabled(bool enabled) = 0;
|
||||
virtual void resetDownlinkedPacketCount() = 0;
|
||||
virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */
|
||||
|
15
src/fsfw/tmstorage/TmStoreFrontendSimpleIF.h
Normal file
15
src/fsfw/tmstorage/TmStoreFrontendSimpleIF.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
|
||||
#define FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_
|
||||
|
||||
#include <fsfw/ipc/messageQueueDefinitions.h>
|
||||
|
||||
class TmStoreFrontendSimpleIF {
|
||||
public:
|
||||
virtual ~TmStoreFrontendSimpleIF() = default;
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ */
|
@ -1,6 +1,10 @@
|
||||
#ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_
|
||||
#define FSFW_TMSTORAGE_TMSTOREPACKETS_H_
|
||||
|
||||
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "fsfw/globalfunctions/timevalOperations.h"
|
||||
#include "fsfw/serialize/SerialBufferAdapter.h"
|
||||
#include "fsfw/serialize/SerialFixedArrayListAdapter.h"
|
||||
@ -24,7 +28,7 @@ class ServiceSubservice : public SerialLinkedListAdapter<SerializeIF> {
|
||||
|
||||
class ApidSsc : public SerializeIF {
|
||||
public:
|
||||
ApidSsc() : apid(SpacePacketBase::LIMIT_APID), ssc(0) {}
|
||||
ApidSsc() : apid(ccsds::LIMIT_APID), ssc(0) {}
|
||||
ApidSsc(uint16_t apid, uint16_t ssc) : apid(apid), ssc(ssc) {}
|
||||
uint16_t apid;
|
||||
uint16_t ssc;
|
||||
@ -62,51 +66,59 @@ class ChangeSelectionDefinition : public SerialLinkedListAdapter<SerializeIF> {
|
||||
|
||||
class TmPacketInformation : public SerializeIF {
|
||||
public:
|
||||
TmPacketInformation(TmPacketMinimal* packet) { setContent(packet); }
|
||||
TmPacketInformation()
|
||||
: apid(SpacePacketBase::LIMIT_APID),
|
||||
TmPacketInformation(PusTmReader* packet, size_t timestampLen) : rawTimestamp(timestampLen) {
|
||||
setContent(packet);
|
||||
}
|
||||
TmPacketInformation(size_t timestampLen)
|
||||
: apid(ccsds::LIMIT_APID),
|
||||
sourceSequenceCount(0),
|
||||
serviceType(0),
|
||||
serviceSubtype(0),
|
||||
subCounter(0) {}
|
||||
subCounter(0),
|
||||
rawTimestamp(timestampLen) {}
|
||||
void reset() {
|
||||
apid = SpacePacketBase::LIMIT_APID;
|
||||
apid = ccsds::LIMIT_APID;
|
||||
sourceSequenceCount = 0;
|
||||
serviceType = 0;
|
||||
serviceSubtype = 0;
|
||||
subCounter = 0;
|
||||
memset(rawTimestamp, 0, sizeof(rawTimestamp));
|
||||
memset(rawTimestamp.data(), 0, rawTimestamp.size());
|
||||
}
|
||||
void setContent(TmPacketMinimal* packet) {
|
||||
apid = packet->getAPID();
|
||||
sourceSequenceCount = packet->getPacketSequenceCount();
|
||||
void setContent(PusTmReader* packet) {
|
||||
apid = packet->getApid();
|
||||
sourceSequenceCount = packet->getSequenceCount();
|
||||
serviceType = packet->getService();
|
||||
serviceSubtype = packet->getSubService();
|
||||
subCounter = packet->getPacketSubcounter();
|
||||
memset(rawTimestamp, 0, sizeof(rawTimestamp));
|
||||
const uint8_t* pField = NULL;
|
||||
uint32_t size = 0;
|
||||
ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size);
|
||||
if (result != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) {
|
||||
// Shortcut to avoid converting CDS back and forth.
|
||||
memcpy(rawTimestamp, pField, size);
|
||||
return;
|
||||
}
|
||||
timeval time = {0, 0};
|
||||
result = packet->getPacketTime(&time);
|
||||
if (result != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
CCSDSTime::CDS_short cdsFormat;
|
||||
result = CCSDSTime::convertToCcsds(&cdsFormat, &time);
|
||||
if (result != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat));
|
||||
subCounter = packet->getMessageTypeCounter();
|
||||
memset(rawTimestamp.data(), 0, rawTimestamp.size());
|
||||
// TODO: Fix all of this
|
||||
// const uint8_t* pField = NULL;
|
||||
// uint32_t size = 0;
|
||||
// auto* timeReader = packet->getTimeReader();
|
||||
// ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size);
|
||||
// if (result != returnvalue::OK) {
|
||||
// return;
|
||||
//}
|
||||
// if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE)
|
||||
// {
|
||||
// Shortcut to avoid converting CDS back and forth.
|
||||
// TODO: Fix
|
||||
// memcpy(rawTimestamp, pField, size);
|
||||
// return;
|
||||
// }
|
||||
// timeval time = {0, 0};
|
||||
// result = packet->getPacketTime(&time);
|
||||
// if (result != returnvalue::OK) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// CCSDSTime::CDS_short cdsFormat;
|
||||
// result = CCSDSTime::convertToCcsds(&cdsFormat, &time);
|
||||
// if (result != returnvalue::OK) {
|
||||
// return;
|
||||
// }
|
||||
// TODO: Fix
|
||||
// memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat));
|
||||
}
|
||||
void setContent(TmPacketInformation* content) {
|
||||
apid = content->apid;
|
||||
@ -114,9 +126,10 @@ class TmPacketInformation : public SerializeIF {
|
||||
serviceType = content->serviceType;
|
||||
serviceSubtype = content->serviceSubtype;
|
||||
subCounter = content->subCounter;
|
||||
memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp));
|
||||
// TODO: Fix
|
||||
// memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp));
|
||||
}
|
||||
bool isValid() const { return (apid < SpacePacketBase::LIMIT_APID) ? true : false; }
|
||||
bool isValid() const { return (apid < ccsds::LIMIT_APID) ? true : false; }
|
||||
static void reset(TmPacketInformation* packet) { packet->reset(); }
|
||||
|
||||
static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime) {
|
||||
@ -216,7 +229,7 @@ class TmPacketInformation : public SerializeIF {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp));
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
|
||||
return adapter.serialize(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
|
||||
@ -227,7 +240,7 @@ class TmPacketInformation : public SerializeIF {
|
||||
size += SerializeAdapter::getSerializedSize(&serviceType);
|
||||
size += SerializeAdapter::getSerializedSize(&serviceSubtype);
|
||||
size += SerializeAdapter::getSerializedSize(&subCounter);
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp));
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
|
||||
size += adapter.getSerializedSize();
|
||||
return size;
|
||||
};
|
||||
@ -253,7 +266,7 @@ class TmPacketInformation : public SerializeIF {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp, sizeof(rawTimestamp));
|
||||
SerialBufferAdapter<uint8_t> adapter(rawTimestamp.data(), rawTimestamp.size());
|
||||
return adapter.deSerialize(buffer, size, streamEndianness);
|
||||
}
|
||||
|
||||
@ -263,6 +276,6 @@ class TmPacketInformation : public SerializeIF {
|
||||
uint8_t serviceType;
|
||||
uint8_t serviceSubtype;
|
||||
uint8_t subCounter;
|
||||
uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE];
|
||||
std::vector<uint8_t> rawTimestamp;
|
||||
};
|
||||
#endif /* FSFW_TMSTORAGE_TMSTOREPACKETS_H_ */
|
||||
|
@ -40,7 +40,7 @@ struct PusTmParams {
|
||||
size_t dataLen)
|
||||
: secHeader(service, subservice, timeStamper), adapter(data, dataLen), sourceData(&adapter) {}
|
||||
PusTmSecHeader secHeader;
|
||||
SerialBufferAdapter<uint8_t> adapter;
|
||||
SerialBufferAdapter<size_t> adapter;
|
||||
const SerializeIF* sourceData = nullptr;
|
||||
};
|
||||
|
||||
|
@ -24,3 +24,9 @@ void PusTmZeroCopyWriter::updateErrorControl() {
|
||||
crcStart[0] = (crc16 >> 8) & 0xff;
|
||||
crcStart[1] = crc16 & 0xff;
|
||||
}
|
||||
|
||||
void PusTmZeroCopyWriter::setMessageCount(uint16_t msgCount) {
|
||||
size_t serSize = 0;
|
||||
SerializeAdapter::serialize(&msgCount, const_cast<uint8_t*>(pointers.secHeaderStart + 3),
|
||||
&serSize, 2, SerializeIF::Endianness::NETWORK);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ class PusTmZeroCopyWriter : public PusTmReader {
|
||||
PusTmZeroCopyWriter(TimeReaderIF& timeReader, uint8_t* data, size_t size);
|
||||
|
||||
void setSequenceCount(uint16_t seqCount);
|
||||
void setMessageCount(uint16_t msgCount);
|
||||
void updateErrorControl();
|
||||
|
||||
private:
|
||||
|
@ -8,7 +8,7 @@
|
||||
#define TMTCBRIDGE_WIRETAPPING 0
|
||||
|
||||
TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
||||
object_id_t tmStoreId, object_id_t tcStoreId)
|
||||
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
|
||||
: SystemObject(objectId),
|
||||
name(name),
|
||||
tmStoreId(tmStoreId),
|
||||
@ -18,7 +18,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
|
||||
{
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
||||
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||
|
@ -15,15 +15,14 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
public ExecutableObjectIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
|
||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 1000;
|
||||
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500;
|
||||
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||
|
||||
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
||||
object_id_t tmStoreId, object_id_t tcStoreId);
|
||||
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId);
|
||||
~TmTcBridge() override;
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "version.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/FSFWVersion.h"
|
||||
|
||||
@ -20,7 +21,7 @@ fsfw::Version::Version(int major, int minor, int revision, const char* addInfo)
|
||||
|
||||
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
||||
if (addInfo != nullptr) {
|
||||
if (addInfo != nullptr and std::strcmp(addInfo, "") != 0) {
|
||||
snprintf(str + len, maxLen - len, "-%s", addInfo);
|
||||
}
|
||||
}
|
||||
@ -30,7 +31,7 @@ namespace fsfw {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
||||
os << v.major << "." << v.minor << "." << v.revision;
|
||||
if (v.addInfo != nullptr) {
|
||||
if (v.addInfo != nullptr and std::strcmp(v.addInfo, "") != 0) {
|
||||
os << "-" << v.addInfo;
|
||||
}
|
||||
return os;
|
||||
|
@ -5,8 +5,18 @@
|
||||
|
||||
namespace spi {
|
||||
|
||||
static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI;
|
||||
static constexpr ReturnValue_t OPENING_FILE_FAILED = returnvalue::makeCode(CLASS_ID, 0);
|
||||
/* Full duplex (ioctl) transfer failure */
|
||||
static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = returnvalue::makeCode(CLASS_ID, 1);
|
||||
/* Half duplex (read/write) transfer failure */
|
||||
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = returnvalue::makeCode(CLASS_ID, 2);
|
||||
static constexpr ReturnValue_t TIMEOUT = returnvalue::makeCode(CLASS_ID, 3);
|
||||
static constexpr ReturnValue_t BUSY = returnvalue::makeCode(CLASS_ID, 4);
|
||||
static constexpr ReturnValue_t GENERIC_ERROR = returnvalue::makeCode(CLASS_ID, 5);
|
||||
|
||||
enum SpiModes : uint8_t { MODE_0, MODE_1, MODE_2, MODE_3 };
|
||||
|
||||
}
|
||||
} // namespace spi
|
||||
|
||||
#endif /* FSFW_HAL_COMMON_SPI_SPICOMMON_H_ */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user