Compare commits
140 Commits
mueller/ne
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
515c66a780 | |||
8c20417af9 | |||
ac817f296b | |||
622ad9ff18
|
|||
f0e4eacac5
|
|||
acc737feb2 | |||
c9281a3760
|
|||
cc97c7f82d
|
|||
a3b102c0d0
|
|||
5dd4f15b39 | |||
b5a3c0226e | |||
e925b8595c
|
|||
c5bf5389b8 | |||
7285dd6bac
|
|||
b53bf2ea12 | |||
610c196f6d | |||
ece47b4f2f | |||
3f777c54fe | |||
3d54895251
|
|||
d91e1ecc0a | |||
e5910c77e9
|
|||
1569416a8f
|
|||
278c8f1186
|
|||
60f6ef5f1f
|
|||
4ecd9eb62e | |||
fb89d7a3b6 | |||
146c3471d0 | |||
1816c3f623 | |||
d03d5aa74c | |||
26e97ddf89 | |||
be3a57a795 | |||
13b97abf0d | |||
f95c373076 | |||
e03731bcf8 | |||
9fe8579377 | |||
2714e588d7 | |||
e905288adc | |||
3805ea50a7 | |||
699bd694cd | |||
4518fec65c | |||
dac1aacab2 | |||
0042f92fdf | |||
656faf8169 | |||
f84431e965 | |||
0cec9ebb73 | |||
a440b7c394 | |||
bbfc1b2b34 | |||
025b379e8b
|
|||
c35a0a8541 | |||
0f81d5e458 | |||
e0a072859b | |||
b50f092939 | |||
2f90e12179 | |||
8b77fac099 | |||
47503824d7 | |||
5e3f5c4121 | |||
1f36c082ef | |||
aa84e93603 | |||
8f63a0e747 | |||
6fc8f756a7 | |||
067cb7d0f8 | |||
d98ed40e3d | |||
2c17af4ef8 | |||
110fb43b9c | |||
b057250bfb | |||
066dd0d397 | |||
f735c2e9d4 | |||
dc7afc5415 | |||
9bf3ff95b7 | |||
61562b18ab | |||
d76d97a36b | |||
76b377c4c0 | |||
3562bf11b9 | |||
fffb2b61e5 | |||
94e5f62331 | |||
0a9c563bbc | |||
fa7675897d | |||
3a2393885f | |||
c752b6d143 | |||
b676040c7c | |||
010509efb4 | |||
dfb1633f00 | |||
5f7172e130 | |||
0c6465cd95 | |||
f94987c46d | |||
1809ce359b | |||
8c712441ab | |||
f1b0ca7cff | |||
000df85556 | |||
1fffcc2229 | |||
a419806a05 | |||
6445debfa1 | |||
8014e4adf9 | |||
134d908f26 | |||
40a9e12416 | |||
f39054edd4 | |||
5adf89b911 | |||
c2e6a22dec | |||
c8e065a713 | |||
3ed49dbae3 | |||
4cf52d5dfe | |||
539d7aac9e | |||
0a23f2c85a | |||
46230e6c6d | |||
b22d439300 | |||
7e7b3bbbc9 | |||
5b92247fbd | |||
e2b66df72e | |||
d9da55fdab | |||
7b828f233a | |||
c3d1000cd5 | |||
8e0e57714d | |||
066f7a6f9b | |||
cc9e54ea6b | |||
31465a4e0f | |||
c0e5d1eb99 | |||
3bc5d4a2e0 | |||
b1e9dd9e4a | |||
ab86599db3 | |||
034eb34c2e | |||
4374c7c4f4 | |||
5343844be5 | |||
e300490b93 | |||
0f811777a7 | |||
e93137939e | |||
c1f42618db | |||
1f88c006d9 | |||
7e94baceef | |||
61df451dd8 | |||
29ea89044e | |||
e487f5be87 | |||
9b05e8f274 | |||
eb223dae88 | |||
3656662d88 | |||
fe71978467 | |||
b646717a76 | |||
99d8c845f2 | |||
0e7c6b117f | |||
ba62c28b64 | |||
7adb47aecb |
167
CHANGELOG.md
167
CHANGELOG.md
@ -8,14 +8,74 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [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
|
||||||
|
- Important bugfix for `LocalPool::delete` function, where an overflow could possibly lead to UB.
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- add CFDP subsystem ID
|
||||||
|
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||||
|
- New object ID for persistent TM store PUS 15
|
||||||
|
- `EventManager`: Add function to print all listeners.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- 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
|
||||||
|
- `EventManager`: Queue depth is configurable now
|
||||||
|
- `ActionHelper`: Allow execution of actions without additional data
|
||||||
|
|
||||||
|
# [v6.0.0] 2023-02-10
|
||||||
|
|
||||||
## Fixes
|
## 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.
|
- 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
|
- Only delete health table entry in `HealthHelper` destructor if
|
||||||
health table was set.
|
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.
|
- 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.
|
Also properly reset the reply size for successfull transfers and erroneous transfers.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
|
||||||
@ -25,22 +85,82 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
- `TcpTmTcServer.cpp`: The server was actually not able to handle
|
||||||
CCSDS packets which were clumped together. This has been fixed now.
|
CCSDS packets which were clumped together. This has been fixed now.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
|
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
|
## Added
|
||||||
|
|
||||||
|
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
|
||||||
|
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
||||||
|
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
|
||||||
|
option on the TCP server. CTOR prototype has changed and expects an explicit
|
||||||
|
TCP configuration struct to be passed.
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
|
||||||
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
||||||
- `UioMapper` is able to resolve symlinks now.
|
- `UioMapper` is able to resolve symlinks now.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
|
||||||
- Add new `UnsignedByteField` class
|
- Add new `UnsignedByteField` class
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
|
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
|
## Changes
|
||||||
|
|
||||||
|
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
|
||||||
|
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
|
||||||
|
`HealthServiceCfg` now
|
||||||
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
|
||||||
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
|
||||||
- Moved some container returnvalues to dedicated header and namespace
|
- 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
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
|
||||||
- Remove default secondary header argument for
|
- Remove default secondary header argument for
|
||||||
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
|
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
|
||||||
@ -70,18 +190,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
|
||||||
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
|
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`:
|
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
|
||||||
- Make functions `const` where it makes sense
|
- Make functions `const` where it makes sense
|
||||||
- Add `const char* getName const` abstract function
|
- Add `const char* getName const` abstract function
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
|
||||||
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
- Generic TMTC Bridge Update
|
||||||
interface itself so it can be re-used more easily. Also add new
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
||||||
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
- comment tweak to event parser can read everything
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
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
|
## CFDP
|
||||||
|
|
||||||
@ -101,7 +244,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
implementation without an extra component
|
implementation without an extra component
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
|
||||||
|
|
||||||
# [v5.0.0] 25.07.2022
|
# [v5.0.0] 2022-07-25
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
|||||||
# Version file handling #
|
# 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_SUBVERSION_IF_GIT_FAILS 0)
|
||||||
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
set(FSFW_REVISION_IF_GIT_FAILS 0)
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ set(FSFW_ETL_LIB_MAJOR_VERSION
|
|||||||
20
|
20
|
||||||
CACHE STRING "ETL library major version requirement")
|
CACHE STRING "ETL library major version requirement")
|
||||||
set(FSFW_ETL_LIB_VERSION
|
set(FSFW_ETL_LIB_VERSION
|
||||||
${FSFW_ETL_LIB_MAJOR_VERSION}.28.0
|
${FSFW_ETL_LIB_MAJOR_VERSION}.36.0
|
||||||
CACHE STRING "ETL library exact version requirement")
|
CACHE STRING "ETL library exact version requirement")
|
||||||
set(FSFW_ETL_LINK_TARGET etl::etl)
|
set(FSFW_ETL_LINK_TARGET etl::etl)
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ set(FSFW_CATCH2_LIB_MAJOR_VERSION
|
|||||||
3
|
3
|
||||||
CACHE STRING "Catch2 library major version requirement")
|
CACHE STRING "Catch2 library major version requirement")
|
||||||
set(FSFW_CATCH2_LIB_VERSION
|
set(FSFW_CATCH2_LIB_VERSION
|
||||||
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.1.0
|
v${FSFW_CATCH2_LIB_MAJOR_VERSION}.3.2
|
||||||
CACHE STRING "Catch2 library exact version requirement")
|
CACHE STRING "Catch2 library exact version requirement")
|
||||||
|
|
||||||
# Keep this off by default for now. See PR:
|
# Keep this off by default for now. See PR:
|
||||||
@ -153,12 +153,12 @@ if(FSFW_BUILD_TESTS)
|
|||||||
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
|
||||||
)
|
)
|
||||||
# Check whether the user has already installed Catch2 first
|
# Check whether the user has already installed Catch2 first
|
||||||
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
|
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET)
|
||||||
# Not installed, so use FetchContent to download and provide Catch2
|
# Not installed, so use FetchContent to download and provide Catch2
|
||||||
if(NOT Catch2_FOUND)
|
if(NOT Catch2_FOUND)
|
||||||
message(
|
message(
|
||||||
STATUS
|
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)
|
include(FetchContent)
|
||||||
|
|
||||||
@ -201,8 +201,8 @@ find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
|||||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||||
message(
|
message(
|
||||||
STATUS
|
STATUS
|
||||||
"${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
|
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent."
|
||||||
"etl with FindPackage")
|
)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
|
@ -7,7 +7,10 @@ RUN apt-get --yes upgrade
|
|||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync
|
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync
|
||||||
|
|
||||||
RUN python3 -m pip install sphinx breathe
|
# This should also install Sphinx
|
||||||
|
COPY docs/requirements.txt .
|
||||||
|
RUN python3 -m pip install -r requirements.txt
|
||||||
|
RUN python3 -m pip install breathe
|
||||||
|
|
||||||
RUN git clone https://github.com/catchorg/Catch2.git && \
|
RUN git clone https://github.com/catchorg/Catch2.git && \
|
||||||
cd Catch2 && \
|
cd Catch2 && \
|
||||||
|
80
automation/Jenkinsfile
vendored
80
automation/Jenkinsfile
vendored
@ -1,82 +1,130 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
environment {
|
environment {
|
||||||
BUILDDIR = 'cmake-build-tests'
|
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||||
|
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||||
DOCDDIR = 'cmake-build-documentation'
|
DOCDDIR = 'cmake-build-documentation'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
image 'fsfw-ci:d6'
|
image 'fsfw-ci:d11'
|
||||||
args '--network host'
|
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
|
stage('Host') {
|
||||||
|
stages{
|
||||||
stage('Clean') {
|
stage('Clean') {
|
||||||
steps {
|
steps {
|
||||||
sh 'rm -rf $BUILDDIR'
|
sh 'rm -rf $BUILDDIR_HOST'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Configure') {
|
stage('Configure') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Build') {
|
stage('Build') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake --build . -j4'
|
sh 'cmake --build . -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Unittests') {
|
stage('Unittests') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Valgrind') {
|
stage('Valgrind') {
|
||||||
steps {
|
steps {
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_HOST) {
|
||||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Linux') {
|
||||||
|
stages{
|
||||||
|
stage('Clean') {
|
||||||
|
steps {
|
||||||
|
sh 'rm -rf $BUILDDIR_LINUX'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Configure') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Unittests') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Valgrind') {
|
||||||
|
steps {
|
||||||
|
dir(BUILDDIR_LINUX) {
|
||||||
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage('Documentation') {
|
stage('Documentation') {
|
||||||
when {
|
when {
|
||||||
branch 'development'
|
anyOf {
|
||||||
|
branch 'development';
|
||||||
|
branch pattern: 'development-doc-deployment*'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
dir(DOCDDIR) {
|
dir(DOCDDIR) {
|
||||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||||
sh 'make Sphinx'
|
sh 'make Sphinx'
|
||||||
sshagent(credentials: ['documentation-buildfix']) {
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/development'
|
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/projects/fsfw/development'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_LINUX) {
|
||||||
sshagent(credentials: ['documentation-buildfix']) {
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/development'
|
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/projects/fsfw/coverage/development'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Master Documentation') {
|
stage('Master Documentation') {
|
||||||
when {
|
when {
|
||||||
branch 'master'
|
anyOf {
|
||||||
|
branch 'master';
|
||||||
|
branch pattern: 'master-doc-deployment*'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
dir(DOCDDIR) {
|
dir(DOCDDIR) {
|
||||||
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
sh 'cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..'
|
||||||
sh 'make Sphinx'
|
sh 'make Sphinx'
|
||||||
sshagent(credentials: ['documentation-buildfix']) {
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/master'
|
sh 'rsync -r --delete docs/sphinx/* buildfix@documentation.irs.uni-stuttgart.de:/projects/fsfw/master'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir(BUILDDIR) {
|
dir(BUILDDIR_LINUX) {
|
||||||
sshagent(credentials: ['documentation-buildfix']) {
|
sshagent(credentials: ['documentation-buildfix']) {
|
||||||
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/fsfw/coverage/master'
|
sh 'rsync -r --delete fsfw-tests_coverage/* buildfix@documentation.irs.uni-stuttgart.de:/projects/fsfw/coverage/master'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ project = "Flight Software Framework"
|
|||||||
copyright = "2021, Institute of Space Systems (IRS)"
|
copyright = "2021, Institute of Space Systems (IRS)"
|
||||||
author = "Institute of Space Systems (IRS)"
|
author = "Institute of Space Systems (IRS)"
|
||||||
|
|
||||||
|
# TODO: Should try to read this from CMakeLists.txt automatically..
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = "5.0.0"
|
release = "5.0.0"
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
#
|
#
|
||||||
html_theme = "alabaster"
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||||
|
1
docs/requirements.txt
Normal file
1
docs/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
sphinx-rtd-theme==1.3.0
|
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,8 +59,12 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; }
|
|||||||
|
|
||||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||||
store_address_t dataAddress) {
|
store_address_t dataAddress) {
|
||||||
|
bool hasAdditionalData = false;
|
||||||
const uint8_t* dataPtr = nullptr;
|
const uint8_t* dataPtr = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
ReturnValue_t result;
|
||||||
|
if (dataAddress != store_address_t::invalid()) {
|
||||||
|
hasAdditionalData = true;
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
CommandMessage reply;
|
CommandMessage reply;
|
||||||
@ -68,8 +72,11 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
|
|||||||
queueToUse->sendMessage(commandedBy, &reply);
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||||
|
if (hasAdditionalData) {
|
||||||
ipcStore->deleteData(dataAddress);
|
ipcStore->deleteData(dataAddress);
|
||||||
|
}
|
||||||
if (result == HasActionsIF::EXECUTION_FINISHED) {
|
if (result == HasActionsIF::EXECUTION_FINISHED) {
|
||||||
CommandMessage reply;
|
CommandMessage reply;
|
||||||
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
ActionMessage::setCompletionReply(&reply, actionId, true, result);
|
||||||
|
@ -16,8 +16,8 @@ class CommandActionHelper {
|
|||||||
public:
|
public:
|
||||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||||
virtual ~CommandActionHelper();
|
virtual ~CommandActionHelper();
|
||||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||||
uint32_t size);
|
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||||
ReturnValue_t initialize();
|
ReturnValue_t initialize();
|
||||||
ReturnValue_t handleReply(CommandMessage* reply);
|
ReturnValue_t handleReply(CommandMessage* reply);
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
#define FSFW_CFDP_H
|
#define FSFW_CFDP_H
|
||||||
|
|
||||||
#include "cfdp/definitions.h"
|
#include "cfdp/definitions.h"
|
||||||
#include "cfdp/handler/CfdpHandler.h"
|
|
||||||
#include "cfdp/handler/DestHandler.h"
|
|
||||||
#include "cfdp/handler/FaultHandlerBase.h"
|
#include "cfdp/handler/FaultHandlerBase.h"
|
||||||
#include "cfdp/helpers.h"
|
|
||||||
#include "cfdp/tlv/Lv.h"
|
#include "cfdp/tlv/Lv.h"
|
||||||
#include "cfdp/tlv/StringLv.h"
|
#include "cfdp/tlv/StringLv.h"
|
||||||
#include "cfdp/tlv/Tlv.h"
|
#include "cfdp/tlv/Tlv.h"
|
||||||
|
@ -51,8 +51,9 @@ class VarLenField : public SerializeIF {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using SerializeIF::deSerialize; // we overloaded above, so this is needed to uncofuse the
|
||||||
|
// compiler
|
||||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
|
|
||||||
|
@ -1,3 +1 @@
|
|||||||
target_sources(
|
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||||
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
|
||||||
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.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
|
|
@ -1,490 +0,0 @@
|
|||||||
#include "DestHandler.h"
|
|
||||||
|
|
||||||
#include <etl/crc32.h>
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "fsfw/FSFW.h"
|
|
||||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
|
||||||
#include "fsfw/objectmanager.h"
|
|
||||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
|
||||||
|
|
||||||
using namespace returnvalue;
|
|
||||||
|
|
||||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
|
||||||
: tlvVec(params.maxTlvsInOnePdu),
|
|
||||||
userTlvVec(params.maxTlvsInOnePdu),
|
|
||||||
dp(std::move(params)),
|
|
||||||
fp(fsfwParams),
|
|
||||||
tp(params.maxFilenameLen) {
|
|
||||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
|
||||||
ReturnValue_t result;
|
|
||||||
uint8_t errorIdx = 0;
|
|
||||||
fsmRes.resetOfIteration();
|
|
||||||
if (fsmRes.step == TransactionStep::IDLE) {
|
|
||||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
|
||||||
infoIter->directiveType == FileDirective::METADATA) {
|
|
||||||
result = handleMetadataPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.packetListRef.erase(infoIter++);
|
|
||||||
} else {
|
|
||||||
infoIter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::IDLE) {
|
|
||||||
// To decrease the already high complexity of the software, all packets arriving before
|
|
||||||
// a metadata PDU are deleted.
|
|
||||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
fp.tcStore->deleteData(infoIter->storeId);
|
|
||||||
infoIter++;
|
|
||||||
}
|
|
||||||
dp.packetListRef.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsmRes.step != TransactionStep::IDLE) {
|
|
||||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
|
||||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
|
||||||
if (infoIter->pduType == PduType::FILE_DATA) {
|
|
||||||
result = handleFileDataPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.packetListRef.erase(infoIter++);
|
|
||||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
|
||||||
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
|
||||||
// TODO: Support for check timer missing
|
|
||||||
result = handleEofPdu(*infoIter);
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
// Store data was deleted in PDU handler because a store guard is used
|
|
||||||
dp.packetListRef.erase(infoIter++);
|
|
||||||
} else {
|
|
||||||
infoIter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
|
||||||
result = handleTransferCompletion();
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
|
||||||
result = sendFinishedPdu();
|
|
||||||
checkAndHandleError(result, errorIdx);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
// TODO: Will be implemented at a later stage
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return updateFsmRes(errorIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
|
||||||
if (dp.packetListRef.full()) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
dp.packetListRef.push_back(packet);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
|
||||||
if (fp.tmStore == nullptr) {
|
|
||||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
|
||||||
if (fp.tmStore == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp.tcStore == nullptr) {
|
|
||||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
|
||||||
if (fp.tcStore == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fp.msgQueue == nullptr) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
|
||||||
// Process metadata PDU
|
|
||||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
|
||||||
if (constAccessorPair.first != OK) {
|
|
||||||
// TODO: This is not a CFDP error. Event and/or warning?
|
|
||||||
return constAccessorPair.first;
|
|
||||||
}
|
|
||||||
cfdp::StringLv sourceFileName;
|
|
||||||
cfdp::StringLv destFileName;
|
|
||||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
|
||||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
|
||||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
|
||||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
|
||||||
metadataInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
// TODO: The standard does not really specify what happens if this kind of error happens
|
|
||||||
// I think it might be a good idea to cache some sort of error code, which
|
|
||||||
// is translated into a warning and/or event by an upper layer
|
|
||||||
if (result != OK) {
|
|
||||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
|
||||||
constAccessorPair.second.size());
|
|
||||||
}
|
|
||||||
return startTransaction(reader, metadataInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
|
||||||
// Process file data PDU
|
|
||||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
|
||||||
if (constAccessorPair.first != OK) {
|
|
||||||
// TODO: This is not a CFDP error. Event and/or warning?
|
|
||||||
return constAccessorPair.first;
|
|
||||||
}
|
|
||||||
cfdp::FileSize offset;
|
|
||||||
FileDataInfo fdInfo(offset);
|
|
||||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t fileSegmentLen = 0;
|
|
||||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
|
||||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
|
||||||
fileOpParams.offset = offset.value();
|
|
||||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
|
||||||
FileSegmentRecvdParams segParams;
|
|
||||||
segParams.offset = offset.value();
|
|
||||||
segParams.id = tp.transactionId;
|
|
||||||
segParams.length = fileSegmentLen;
|
|
||||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
|
||||||
size_t segmentMetadatLen = 0;
|
|
||||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
|
||||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
|
||||||
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;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
|
||||||
// Process EOF PDU
|
|
||||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
|
||||||
if (constAccessorPair.first != OK) {
|
|
||||||
// TODO: This is not a CFDP error. Event and/or warning?
|
|
||||||
return constAccessorPair.first;
|
|
||||||
}
|
|
||||||
EofInfo eofInfo(nullptr);
|
|
||||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
|
||||||
ReturnValue_t result = reader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// TODO: Error handling
|
|
||||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
|
||||||
tp.crc = eofInfo.getChecksum();
|
|
||||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
|
||||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
|
||||||
if (fileSizeFromEof > tp.progress) {
|
|
||||||
// TODO: File size error
|
|
||||||
}
|
|
||||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
|
||||||
}
|
|
||||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
|
||||||
dp.user.eofRecvIndication(getTransactionId());
|
|
||||||
}
|
|
||||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
|
||||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
|
||||||
const uint8_t* rawData, size_t maxSize) {
|
|
||||||
// TODO: try to extract destination ID for error
|
|
||||||
// TODO: Invalid metadata PDU.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
PduHeaderReader headerReader(rawData, maxSize);
|
|
||||||
result = headerReader.parseData();
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Now this really should not happen. Warning or error,
|
|
||||||
// yield or cache appropriate returnvalue
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "Parsing Header failed" << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
// TODO: Trigger appropriate event
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
cfdp::EntityId destId;
|
|
||||||
headerReader.getDestId(destId);
|
|
||||||
RemoteEntityCfg* remoteCfg;
|
|
||||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
|
||||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
|
||||||
// covered by the standard.
|
|
||||||
// Warning or error, yield or cache appropriate returnvalue
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
|
||||||
#else
|
|
||||||
#endif
|
|
||||||
// TODO: Trigger appropriate event
|
|
||||||
}
|
|
||||||
// TODO: Appropriate returnvalue?
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
|
||||||
if (fsmRes.state != CfdpStates::IDLE) {
|
|
||||||
// According to standard, discard metadata PDU if we are busy
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
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)) {
|
|
||||||
// TODO: Warning, event etc.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler" << __func__
|
|
||||||
<< ": No remote configuration found for destination ID "
|
|
||||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
|
||||||
#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::RECEIVING_FILE_DATA_PDUS;
|
|
||||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
|
||||||
params.fileSize = tp.fileSize.getSize();
|
|
||||||
params.destFileName = tp.destName.data();
|
|
||||||
params.sourceFileName = tp.sourceName.data();
|
|
||||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
|
||||||
params.msgsToUserLen = info.getOptionsLen();
|
|
||||||
dp.user.metadataRecvdIndication(params);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
|
||||||
ReturnValue_t result;
|
|
||||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
|
||||||
result = checksumVerification();
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: Warning / error handling?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
}
|
|
||||||
result = noticeOfCompletion();
|
|
||||||
if (result != OK) {
|
|
||||||
}
|
|
||||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
|
||||||
if (tp.closureRequested) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
|
||||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::finish() {
|
|
||||||
tp.reset();
|
|
||||||
dp.packetListRef.clear();
|
|
||||||
fsmRes.state = CfdpStates::IDLE;
|
|
||||||
fsmRes.step = TransactionStep::IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
|
||||||
std::array<uint8_t, 1024> buf{};
|
|
||||||
// TODO: Checksum verification and notice of completion
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
uint64_t currentOffset = 0;
|
|
||||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
|
||||||
while (currentOffset < tp.fileSize.value()) {
|
|
||||||
uint64_t readLen;
|
|
||||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
|
||||||
readLen = tp.fileSize.value() - currentOffset;
|
|
||||||
} else {
|
|
||||||
readLen = buf.size();
|
|
||||||
}
|
|
||||||
if (readLen > 0) {
|
|
||||||
params.offset = currentOffset;
|
|
||||||
params.size = readLen;
|
|
||||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
|
||||||
if (result != OK) {
|
|
||||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
|
||||||
// a warning or trigger an event because this should generally not happen
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
|
||||||
}
|
|
||||||
currentOffset += readLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t value = crcCalc.value();
|
|
||||||
if (value == tp.crc) {
|
|
||||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
|
||||||
} else {
|
|
||||||
// TODO: Proper error handling
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
|
||||||
#endif
|
|
||||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
|
||||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
|
||||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
|
||||||
tp.deliveryStatus);
|
|
||||||
dp.user.transactionFinishedIndication(params);
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
|
||||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
|
||||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
|
||||||
store_address_t storeId;
|
|
||||||
uint8_t* dataPtr = nullptr;
|
|
||||||
ReturnValue_t result =
|
|
||||||
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
|
||||||
if (result != OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
|
||||||
#endif
|
|
||||||
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t serLen = 0;
|
|
||||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
|
||||||
if (result != OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
TmTcMessage msg(storeId);
|
|
||||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
|
||||||
if (result != OK) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
|
||||||
#endif
|
|
||||||
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
fsmRes.packetsSent++;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
|
||||||
return fsmRes.step;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
|
||||||
fsmRes.errors = errors;
|
|
||||||
fsmRes.result = OK;
|
|
||||||
if (fsmRes.errors > 0) {
|
|
||||||
fsmRes.result = FAILED;
|
|
||||||
}
|
|
||||||
return fsmRes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
|
||||||
|
|
||||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
|
||||||
if (result != OK and errorIdx < 3) {
|
|
||||||
fsmRes.errorCodes[errorIdx] = result;
|
|
||||||
errorIdx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
|
||||||
|
|
||||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
|
||||||
fp.eventReporter = &reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
|
||||||
|
|
||||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
|
||||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
|
@ -1,202 +0,0 @@
|
|||||||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
|
||||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
|
||||||
|
|
||||||
#include <etl/list.h>
|
|
||||||
#include <etl/set.h>
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "RemoteConfigTableIF.h"
|
|
||||||
#include "UserBase.h"
|
|
||||||
#include "defs.h"
|
|
||||||
#include "fsfw/cfdp/handler/mib.h"
|
|
||||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
|
||||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
|
||||||
#include "fsfw/container/DynamicFIFO.h"
|
|
||||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
|
||||||
#include "fsfw/storagemanager/storeAddress.h"
|
|
||||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
|
||||||
|
|
||||||
namespace cfdp {
|
|
||||||
|
|
||||||
struct PacketInfo {
|
|
||||||
PacketInfo(PduType type, store_address_t storeId,
|
|
||||||
std::optional<FileDirective> directive = std::nullopt)
|
|
||||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
|
||||||
|
|
||||||
PduType pduType = PduType::FILE_DATA;
|
|
||||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
|
||||||
store_address_t storeId = store_address_t::invalid();
|
|
||||||
PacketInfo() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <size_t SIZE>
|
|
||||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
|
||||||
template <size_t SIZE>
|
|
||||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
|
||||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
|
||||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
|
||||||
|
|
||||||
struct DestHandlerParams {
|
|
||||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
|
||||||
PacketInfoListBase& packetList,
|
|
||||||
// TODO: This container can potentially take tons of space. For a better
|
|
||||||
// memory efficient implementation, an additional abstraction could be
|
|
||||||
// be used so users can use uint32_t as the pair type
|
|
||||||
LostSegmentsListBase& lostSegmentsContainer)
|
|
||||||
: cfg(std::move(cfg)),
|
|
||||||
user(user),
|
|
||||||
remoteCfgTable(remoteCfgTable),
|
|
||||||
packetListRef(packetList),
|
|
||||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
|
||||||
|
|
||||||
LocalEntityCfg cfg;
|
|
||||||
UserBase& user;
|
|
||||||
RemoteConfigTableIF& remoteCfgTable;
|
|
||||||
|
|
||||||
PacketInfoListBase& packetListRef;
|
|
||||||
LostSegmentsListBase& lostSegmentsContainer;
|
|
||||||
uint8_t maxTlvsInOnePdu = 10;
|
|
||||||
size_t maxFilenameLen = 255;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FsfwParams {
|
|
||||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
|
||||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
|
||||||
StorageManagerIF& tmStore)
|
|
||||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
|
||||||
this->tcStore = &tcStore;
|
|
||||||
this->tmStore = &tmStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
|
||||||
EventReportingProxyIF* eventReporter)
|
|
||||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
|
||||||
AcceptsTelemetryIF& packetDest;
|
|
||||||
MessageQueueIF* msgQueue;
|
|
||||||
EventReportingProxyIF* eventReporter = nullptr;
|
|
||||||
StorageManagerIF* tcStore = nullptr;
|
|
||||||
StorageManagerIF* tmStore = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
|
||||||
|
|
||||||
class DestHandler {
|
|
||||||
public:
|
|
||||||
enum class TransactionStep {
|
|
||||||
IDLE = 0,
|
|
||||||
TRANSACTION_START = 1,
|
|
||||||
RECEIVING_FILE_DATA_PDUS = 2,
|
|
||||||
SENDING_ACK_PDU = 3,
|
|
||||||
TRANSFER_COMPLETION = 4,
|
|
||||||
SENDING_FINISHED_PDU = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FsmResult {
|
|
||||||
public:
|
|
||||||
ReturnValue_t result = returnvalue::OK;
|
|
||||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
|
||||||
TransactionStep step = TransactionStep::IDLE;
|
|
||||||
CfdpStates state = CfdpStates::IDLE;
|
|
||||||
uint32_t packetsSent = 0;
|
|
||||||
uint8_t errors = 0;
|
|
||||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
|
||||||
void resetOfIteration() {
|
|
||||||
result = returnvalue::OK;
|
|
||||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
|
||||||
packetsSent = 0;
|
|
||||||
errors = 0;
|
|
||||||
errorCodes.fill(returnvalue::OK);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Will be returned if it is advisable to call the state machine operation call again
|
|
||||||
*/
|
|
||||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
|
||||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
|
||||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
|
||||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
|
||||||
*/
|
|
||||||
const FsmResult& performStateMachine();
|
|
||||||
void setMsgQueue(MessageQueueIF& queue);
|
|
||||||
void setEventReporter(EventReportingProxyIF& reporter);
|
|
||||||
|
|
||||||
ReturnValue_t passPacket(PacketInfo packet);
|
|
||||||
|
|
||||||
ReturnValue_t initialize();
|
|
||||||
|
|
||||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
|
||||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
|
||||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
|
||||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
|
||||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
|
||||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct TransactionParams {
|
|
||||||
// Initialize char vectors with length + 1 for 0 termination
|
|
||||||
explicit TransactionParams(size_t maxFileNameLen)
|
|
||||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
pduConf = PduConfig();
|
|
||||||
transactionId = TransactionId();
|
|
||||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
|
||||||
std::fill(destName.begin(), destName.end(), '\0');
|
|
||||||
fileSize.setFileSize(0, false);
|
|
||||||
conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
|
||||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
|
||||||
crc = 0;
|
|
||||||
progress = 0;
|
|
||||||
remoteCfg = nullptr;
|
|
||||||
closureRequested = false;
|
|
||||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
|
||||||
bool closureRequested = false;
|
|
||||||
std::vector<char> sourceName;
|
|
||||||
std::vector<char> destName;
|
|
||||||
cfdp::FileSize fileSize;
|
|
||||||
TransactionId transactionId;
|
|
||||||
PduConfig pduConf;
|
|
||||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
|
||||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
|
||||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
|
||||||
uint32_t crc = 0;
|
|
||||||
uint64_t progress = 0;
|
|
||||||
RemoteEntityCfg* remoteCfg = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<cfdp::Tlv> tlvVec;
|
|
||||||
std::vector<cfdp::Tlv> userTlvVec;
|
|
||||||
DestHandlerParams dp;
|
|
||||||
FsfwParams fp;
|
|
||||||
TransactionParams tp;
|
|
||||||
FsmResult fsmRes;
|
|
||||||
|
|
||||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
|
||||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
|
||||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
|
||||||
size_t maxSize);
|
|
||||||
ReturnValue_t handleTransferCompletion();
|
|
||||||
ReturnValue_t sendFinishedPdu();
|
|
||||||
ReturnValue_t noticeOfCompletion();
|
|
||||||
ReturnValue_t checksumVerification();
|
|
||||||
const FsmResult& updateFsmRes(uint8_t errors);
|
|
||||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
|
||||||
void finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cfdp
|
|
||||||
|
|
||||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
|
@ -1 +0,0 @@
|
|||||||
#include "SourceHandler.h"
|
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
||||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
||||||
|
|
||||||
class SourceHandler {};
|
|
||||||
|
|
||||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
|
@ -5,15 +5,5 @@ namespace cfdp {
|
|||||||
|
|
||||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||||
|
|
||||||
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
|
|
||||||
} // namespace cfdp
|
|
||||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||||
|
@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma
|
|||||||
*buffer += 1;
|
*buffer += 1;
|
||||||
**buffer = pduDataFieldLen & 0x00ff;
|
**buffer = pduDataFieldLen & 0x00ff;
|
||||||
*buffer += 1;
|
*buffer += 1;
|
||||||
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
|
**buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) |
|
||||||
pduConf.seqNum.getWidth();
|
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
|
||||||
*buffer += 1;
|
*buffer += 1;
|
||||||
*size += 4;
|
*size += 4;
|
||||||
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);
|
ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness);
|
||||||
|
@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() 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 {
|
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 {
|
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
||||||
|
@ -23,6 +23,8 @@ class EntityIdTlv : public TlvIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
||||||
|
|
||||||
|
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||||
|
// the compiler
|
||||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ class FilestoreResponseTlv : public cfdp::FilestoreTlvBase {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness);
|
ReturnValue_t deSerialize(const cfdp::Tlv& tlv, Endianness endianness);
|
||||||
|
|
||||||
|
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||||
|
// the compiler
|
||||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
|||||||
class FixedArrayList : public ArrayList<T, count_t> {
|
class FixedArrayList : public ArrayList<T, count_t> {
|
||||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||||
"count_t is not large enough to hold MAX_SIZE");
|
"count_t is not large enough to hold MAX_SIZE");
|
||||||
|
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T data[MAX_SIZE];
|
T data[MAX_SIZE];
|
||||||
|
@ -155,8 +155,8 @@ class FixedMap : public SerializeIF {
|
|||||||
|
|
||||||
uint32_t maxSize() const { return theMap.maxSize(); }
|
uint32_t maxSize() const { return theMap.maxSize(); }
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const {
|
Endianness streamEndianness) const override {
|
||||||
ReturnValue_t result =
|
ReturnValue_t result =
|
||||||
SerializeAdapter::serialize(&this->_size, buffer, size, maxSize, streamEndianness);
|
SerializeAdapter::serialize(&this->_size, buffer, size, maxSize, streamEndianness);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
@ -170,7 +170,7 @@ class FixedMap : public SerializeIF {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
size_t getSerializedSize() const override {
|
||||||
uint32_t printSize = sizeof(_size);
|
uint32_t printSize = sizeof(_size);
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
@ -182,8 +182,8 @@ class FixedMap : public SerializeIF {
|
|||||||
return printSize;
|
return printSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) {
|
Endianness streamEndianness) override {
|
||||||
ReturnValue_t result =
|
ReturnValue_t result =
|
||||||
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
|
SerializeAdapter::deSerialize(&this->_size, buffer, size, streamEndianness);
|
||||||
if (this->_size > theMap.maxSize()) {
|
if (this->_size > theMap.maxSize()) {
|
||||||
|
@ -64,7 +64,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
|||||||
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
|
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling
|
||||||
* commit() in between
|
* commit() in between
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||||
uint32_t lockTimeout = 20) override;
|
uint32_t lockTimeout = 20) override;
|
||||||
/**
|
/**
|
||||||
* @brief The commit call initializes writing back the registered variables.
|
* @brief The commit call initializes writing back the registered variables.
|
||||||
@ -84,7 +84,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
|||||||
* - @c COMMITING_WITHOUT_READING if set was not read yet and
|
* - @c COMMITING_WITHOUT_READING if set was not read yet and
|
||||||
* contains non write-only variables
|
* contains non write-only variables
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||||
uint32_t lockTimeout = 20) override;
|
uint32_t lockTimeout = 20) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +92,7 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
|||||||
* @param variable
|
* @param variable
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t registerVariable(PoolVariableIF* variable) override;
|
ReturnValue_t registerVariable(PoolVariableIF* variable) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the means to lock the underlying data structure to ensure
|
* Provides the means to lock the underlying data structure to ensure
|
||||||
|
@ -87,8 +87,8 @@ class LocalPoolVariable : public LocalPoolObjectBase {
|
|||||||
|
|
||||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndianness) const override;
|
SerializeIF::Endianness streamEndianness) const override;
|
||||||
virtual size_t getSerializedSize() const override;
|
size_t getSerializedSize() const override;
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
SerializeIF::Endianness streamEndianness) override;
|
SerializeIF::Endianness streamEndianness) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,10 +98,10 @@ class LocalPoolVector : public LocalPoolObjectBase {
|
|||||||
T& operator[](size_t i);
|
T& operator[](size_t i);
|
||||||
const T& operator[](size_t i) const;
|
const T& operator[](size_t i) const;
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndiannes) const override;
|
SerializeIF::Endianness streamEndiannes) const override;
|
||||||
virtual size_t getSerializedSize() const override;
|
size_t getSerializedSize() const override;
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
SerializeIF::Endianness streamEndianness) override;
|
SerializeIF::Endianness streamEndianness) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||||
|
|
||||||
|
#include "fsfw/datapool/PoolReadGuard.h"
|
||||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||||
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
|
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
|
||||||
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
|
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
|
||||||
@ -1508,9 +1509,12 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
|
|||||||
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
|
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
|
||||||
for (const auto& reply : deviceReplyMap) {
|
for (const auto& reply : deviceReplyMap) {
|
||||||
if (reply.second.dataSet != nullptr) {
|
if (reply.second.dataSet != nullptr) {
|
||||||
|
PoolReadGuard pg(reply.second.dataSet);
|
||||||
|
if (pg.getReadResult() == returnvalue::OK) {
|
||||||
reply.second.dataSet->setValidity(false, true);
|
reply.second.dataSet->setValidity(false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName,
|
void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType, const char* functionName,
|
||||||
|
@ -15,14 +15,16 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
|||||||
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
|
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)},
|
||||||
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}};
|
{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) {
|
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||||
EventMessage::EVENT_MESSAGE_SIZE);
|
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager() {
|
EventManager::~EventManager() {
|
||||||
|
listenerList.clear();
|
||||||
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
|
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
|
||||||
MutexFactory::instance()->deleteMutex(mutex);
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
}
|
}
|
||||||
@ -46,9 +48,20 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
|||||||
|
|
||||||
void EventManager::notifyListeners(EventMessage* message) {
|
void EventManager::notifyListeners(EventMessage* message) {
|
||||||
lockMutex();
|
lockMutex();
|
||||||
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
|
for (auto& listener : listenerList) {
|
||||||
if (iter->second.match(message)) {
|
if (listener.second.match(message)) {
|
||||||
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
|
ReturnValue_t result =
|
||||||
|
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||||
|
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||||
|
<< result << std::setfill(' ') << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||||
|
listener.first, result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlockMutex();
|
unlockMutex();
|
||||||
@ -61,9 +74,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
|
|||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
|
||||||
|
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
|
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
|
||||||
return subscribeToEventRange(listener, event);
|
return subscribeToEventRange(listener, event);
|
||||||
}
|
}
|
||||||
@ -194,4 +212,19 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EventManager::printListeners() {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
|
||||||
|
for (auto& listener : listenerList) {
|
||||||
|
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
|
||||||
|
}
|
||||||
|
sif::info << std::dec << std::setfill(' ');
|
||||||
|
#else
|
||||||
|
sif::printInfo("Event manager listener MQ IDs:\n");
|
||||||
|
for (auto& listener : listenerList) {
|
||||||
|
sif::printInfo("0x%08x\n", listener.first);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
||||||
|
@ -21,9 +21,7 @@ extern const char* translateEvents(Event event);
|
|||||||
|
|
||||||
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject {
|
||||||
public:
|
public:
|
||||||
static const uint16_t MAX_EVENTS_PER_CYCLE = 80;
|
EventManager(object_id_t setObjectId, uint32_t eventQueueDepth);
|
||||||
|
|
||||||
EventManager(object_id_t setObjectId);
|
|
||||||
virtual ~EventManager();
|
virtual ~EventManager();
|
||||||
|
|
||||||
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||||
@ -31,6 +29,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
|||||||
MessageQueueId_t getEventReportQueue();
|
MessageQueueId_t getEventReportQueue();
|
||||||
|
|
||||||
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
|
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
|
||||||
|
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
|
||||||
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
|
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
|
||||||
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
|
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
|
||||||
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||||
@ -43,6 +42,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
|||||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||||
bool reporterInverted = false);
|
bool reporterInverted = false);
|
||||||
ReturnValue_t performOperation(uint8_t opCode);
|
ReturnValue_t performOperation(uint8_t opCode);
|
||||||
|
void printListeners();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MessageQueueIF* eventReportQueue = nullptr;
|
MessageQueueIF* eventReportQueue = nullptr;
|
||||||
|
@ -18,6 +18,7 @@ class EventManagerIF {
|
|||||||
|
|
||||||
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
|
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
|
||||||
bool forwardAllButSelected = false) = 0;
|
bool forwardAllButSelected = false) = 0;
|
||||||
|
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
|
||||||
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
||||||
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
||||||
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
||||||
|
@ -10,7 +10,7 @@ enum : uint8_t {
|
|||||||
CDH = 28,
|
CDH = 28,
|
||||||
TCS_1 = 59,
|
TCS_1 = 59,
|
||||||
PCDU_1 = 42,
|
PCDU_1 = 42,
|
||||||
PCDU_2 = 43,
|
POWER_SWITCH_IF = 43,
|
||||||
HEATER = 50,
|
HEATER = 50,
|
||||||
T_SENSORS = 52,
|
T_SENSORS = 52,
|
||||||
FDIR = 70,
|
FDIR = 70,
|
||||||
|
@ -23,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() {
|
|||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
manager->unregisterListener(eventQueue->getId());
|
||||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,12 +44,12 @@ class Type : public SerializeIF {
|
|||||||
|
|
||||||
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
|
static ActualType_t getActualType(uint8_t ptc, uint8_t pfc);
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||||
Endianness streamEndianness) const override;
|
Endianness streamEndianness) const override;
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const override;
|
size_t getSerializedSize() const override;
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
|||||||
MatchTree(iterator root, uint8_t maxDepth = -1)
|
MatchTree(iterator root, uint8_t maxDepth = -1)
|
||||||
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
||||||
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
||||||
virtual ~MatchTree() {}
|
virtual ~MatchTree() { clear(); }
|
||||||
virtual bool match(T number) override { return matchesTree(number); }
|
virtual bool match(T number) override { return matchesTree(number); }
|
||||||
bool matchesTree(T number) {
|
bool matchesTree(T number) {
|
||||||
iterator iter = this->begin();
|
iterator iter = this->begin();
|
||||||
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
|||||||
return cleanUpElement(position);
|
return cleanUpElement(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
|
||||||
|
|
||||||
|
if (localRoot == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* node = localRoot->left;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (node->left != nullptr) {
|
||||||
|
node = node->left;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (node->right != nullptr) {
|
||||||
|
node = node->right;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (node->parent == nullptr) {
|
||||||
|
// this is the root node with no children
|
||||||
|
if (node->value != nullptr) {
|
||||||
|
cleanUpElement(iterator(node));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// leaf
|
||||||
|
{
|
||||||
|
Node* parent = node->parent;
|
||||||
|
if (parent->left == node) {
|
||||||
|
parent->left = nullptr;
|
||||||
|
} else {
|
||||||
|
parent->right = nullptr;
|
||||||
|
}
|
||||||
|
cleanUpElement(iterator(node));
|
||||||
|
node = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
|
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
|
||||||
|
|
||||||
bool matchSubtree(iterator iter, T number) {
|
bool matchSubtree(iterator iter, T number) {
|
||||||
|
@ -16,26 +16,24 @@ class HasHealthIF {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
|
||||||
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
|
static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
|
||||||
|
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3);
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
||||||
|
//! P1: New Health, P2: Old Health
|
||||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||||
static const Event OVERWRITING_HEALTH =
|
//! Assembly overwrites health information of children to keep satellite alive.
|
||||||
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
||||||
//!< satellite alive.
|
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
||||||
static const Event TRYING_RECOVERY =
|
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
||||||
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
//! Recovery is ongoing. Comes twice during recovery.
|
||||||
//!< power-cycle). No parameters.
|
//! P1: 0 for the first, 1 for the second event. P2: 0
|
||||||
static const Event RECOVERY_STEP =
|
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
||||||
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
//! Recovery was completed. Not necessarily successful. No parameters.
|
||||||
//!< 0 for the first, 1 for the second event. P2: 0
|
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
||||||
static const Event RECOVERY_DONE = MAKE_EVENT(
|
|
||||||
12,
|
|
||||||
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
|
|
||||||
|
|
||||||
virtual ~HasHealthIF() {}
|
virtual ~HasHealthIF() {}
|
||||||
|
|
||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
|
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
;
|
|
||||||
|
|
||||||
mapIterator = healthMap.begin();
|
mapIterator = healthMap.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "HealthTableIF.h"
|
#include "HealthTableIF.h"
|
||||||
|
|
||||||
class HealthTable : public HealthTableIF, public SystemObject {
|
class HealthTable : public HealthTableIF, public SystemObject {
|
||||||
|
friend class CServiceHealthCommanding;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit HealthTable(object_id_t objectid);
|
explicit HealthTable(object_id_t objectid);
|
||||||
~HealthTable() override;
|
~HealthTable() override;
|
||||||
|
@ -54,7 +54,7 @@ class HousekeepingSnapshot : public SerializeIF {
|
|||||||
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr)
|
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize, LocalPoolObjectBase* dataSetPtr)
|
||||||
: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr){};
|
: timeStamp(timeStamp), timeStampSize(timeStampSize), updateData(dataSetPtr){};
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const {
|
Endianness streamEndianness) const {
|
||||||
if (timeStamp != nullptr) {
|
if (timeStamp != nullptr) {
|
||||||
/* Endianness will always be MACHINE, so we can simply use memcpy
|
/* Endianness will always be MACHINE, so we can simply use memcpy
|
||||||
@ -70,14 +70,14 @@ class HousekeepingSnapshot : public SerializeIF {
|
|||||||
return updateData->serialize(buffer, size, maxSize, streamEndianness);
|
return updateData->serialize(buffer, size, maxSize, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
size_t getSerializedSize() const {
|
||||||
if (updateData == nullptr) {
|
if (updateData == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return timeStampSize + updateData->getSerializedSize();
|
return timeStampSize + updateData->getSerializedSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
SerializeIF::Endianness streamEndianness) override {
|
SerializeIF::Endianness streamEndianness) override {
|
||||||
if (*size < timeStampSize) {
|
if (*size < timeStampSize) {
|
||||||
return SerializeIF::STREAM_TOO_SHORT;
|
return SerializeIF::STREAM_TOO_SHORT;
|
||||||
|
@ -7,14 +7,17 @@
|
|||||||
|
|
||||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
|
||||||
poolManager(this, commandQueue),
|
poolManager(this, commandQueue),
|
||||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||||
internalErrorDataset(this) {
|
internalErrorDataset(this) {
|
||||||
|
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
InternalErrorReporter::~InternalErrorReporter() {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
||||||
|
}
|
||||||
|
|
||||||
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||||
this->diagnosticPrintout = enable;
|
this->diagnosticPrintout = enable;
|
||||||
|
@ -24,3 +24,19 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason
|
|||||||
message->setParameter(reason);
|
message->setParameter(reason);
|
||||||
message->setParameter2(0);
|
message->setParameter2(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) {
|
||||||
|
Command_t cmd;
|
||||||
|
if (recursive) {
|
||||||
|
cmd = CMD_MODE_ANNOUNCE_RECURSIVELY;
|
||||||
|
} else {
|
||||||
|
cmd = CMD_MODE_ANNOUNCE;
|
||||||
|
}
|
||||||
|
message.setCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModeMessage::setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) {
|
||||||
|
setModeMessage(&message, CMD_MODE_COMMAND, mode, submode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModeMessage::setModeReadMessage(CommandMessage& message) { message.setCommand(CMD_MODE_READ); }
|
||||||
|
@ -45,6 +45,9 @@ class ModeMessage {
|
|||||||
|
|
||||||
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
|
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
|
||||||
Submode_t submode);
|
Submode_t submode);
|
||||||
|
static void setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode);
|
||||||
|
static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
|
||||||
|
static void setModeReadMessage(CommandMessage& message);
|
||||||
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
|
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
|
||||||
static void clear(CommandMessage* message);
|
static void clear(CommandMessage* message);
|
||||||
};
|
};
|
||||||
|
@ -32,9 +32,9 @@ class AbsLimitMonitor : public MonitorBase<T> {
|
|||||||
return returnvalue::OK; // We're not out of range.
|
return returnvalue::OK; // We're not out of range.
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
|
ReturnValue_t getParameter(uint8_t domainId, uint8_t parameterId,
|
||||||
ParameterWrapper *parameterWrapper,
|
ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
|
||||||
const ParameterWrapper *newValues, uint16_t startAtIndex) {
|
uint16_t startAtIndex) override {
|
||||||
ReturnValue_t result = this->MonitorBase<T>::getParameter(
|
ReturnValue_t result = this->MonitorBase<T>::getParameter(
|
||||||
domainId, parameterId, parameterWrapper, newValues, startAtIndex);
|
domainId, parameterId, parameterWrapper, newValues, startAtIndex);
|
||||||
// We'll reuse the DOMAIN_ID of MonitorReporter,
|
// We'll reuse the DOMAIN_ID of MonitorReporter,
|
||||||
|
@ -13,6 +13,7 @@ class MonitoringMessage : public CommandMessage {
|
|||||||
static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10);
|
static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10);
|
||||||
virtual ~MonitoringMessage();
|
virtual ~MonitoringMessage();
|
||||||
static void setLimitViolationReport(CommandMessage* message, store_address_t storeId);
|
static void setLimitViolationReport(CommandMessage* message, store_address_t storeId);
|
||||||
|
using CommandMessage::clear;
|
||||||
static void clear(CommandMessage* message);
|
static void clear(CommandMessage* message);
|
||||||
static store_address_t getStoreId(const CommandMessage* message);
|
static store_address_t getStoreId(const CommandMessage* message);
|
||||||
static void setTypicalMessage(CommandMessage* message, Command_t type, store_address_t storeId);
|
static void setTypicalMessage(CommandMessage* message, Command_t type, store_address_t storeId);
|
||||||
|
@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
|
|||||||
|
|
||||||
ObjectManager::ObjectManager() = default;
|
ObjectManager::ObjectManager() = default;
|
||||||
|
|
||||||
|
void ObjectManager::clear() {
|
||||||
|
if (objManagerInstance != nullptr) {
|
||||||
|
delete objManagerInstance;
|
||||||
|
objManagerInstance = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjectManager::~ObjectManager() {
|
ObjectManager::~ObjectManager() {
|
||||||
for (auto const& iter : objectList) {
|
teardown = true;
|
||||||
delete iter.second;
|
for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
|
||||||
|
delete iter->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t ObjectManager::remove(object_id_t id) {
|
ReturnValue_t ObjectManager::remove(object_id_t id) {
|
||||||
|
// this function is called during destruction of System Objects
|
||||||
|
// disabeld for teardown to avoid iterator invalidation and
|
||||||
|
// double free
|
||||||
|
if (teardown) {
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
if (this->getSystemObject(id) != nullptr) {
|
if (this->getSystemObject(id) != nullptr) {
|
||||||
this->objectList.erase(id);
|
this->objectList.erase(id);
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF {
|
|||||||
using produce_function_t = void (*)(void* args);
|
using produce_function_t = void (*)(void* args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the single instance of TaskFactory.
|
* Returns the single instance of ObjectManager.
|
||||||
* The implementation of #instance is found in its subclasses.
|
* The implementation of #instance is found in its subclasses.
|
||||||
* Thus, we choose link-time variability of the instance.
|
* Thus, we choose link-time variability of the instance.
|
||||||
*/
|
*/
|
||||||
static ObjectManager* instance();
|
static ObjectManager* instance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the single instance of ObjectManager
|
||||||
|
*/
|
||||||
|
static void clear();
|
||||||
|
|
||||||
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
|
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF {
|
|||||||
*/
|
*/
|
||||||
std::map<object_id_t, SystemObjectIF*> objectList;
|
std::map<object_id_t, SystemObjectIF*> objectList;
|
||||||
static ObjectManager* objManagerInstance;
|
static ObjectManager* objManagerInstance;
|
||||||
|
// used when the OM itself is deleted to modify behaviour of remove()
|
||||||
|
// to avoid iterator invalidation and double free
|
||||||
|
bool teardown = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Documentation can be found in the class method declaration above
|
// Documentation can be found in the class method declaration above
|
||||||
|
@ -15,6 +15,7 @@ enum framework_objects : object_id_t {
|
|||||||
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
|
||||||
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
PUS_SERVICE_9_TIME_MGMT = 0x53000009,
|
||||||
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
|
PUS_SERVICE_11_TC_SCHEDULER = 0x53000011,
|
||||||
|
PUS_SERVICE_15_TM_STORAGE = 0x53000015,
|
||||||
PUS_SERVICE_17_TEST = 0x53000017,
|
PUS_SERVICE_17_TEST = 0x53000017,
|
||||||
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
PUS_SERVICE_20_PARAMETERS = 0x53000020,
|
||||||
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
# Check the OS_FSFW variable
|
# Check the OS_FSFW variable
|
||||||
if(FSFW_OSAL MATCHES "freertos")
|
if(FSFW_OSAL MATCHES "freertos")
|
||||||
add_subdirectory(freertos)
|
add_subdirectory(freertos)
|
||||||
|
set(FSFW_OSAL_FREERTOS 1)
|
||||||
elseif(FSFW_OSAL MATCHES "rtems")
|
elseif(FSFW_OSAL MATCHES "rtems")
|
||||||
add_subdirectory(rtems)
|
add_subdirectory(rtems)
|
||||||
|
set(FSFW_OSAL_RTEMS 1)
|
||||||
elseif(FSFW_OSAL MATCHES "linux")
|
elseif(FSFW_OSAL MATCHES "linux")
|
||||||
add_subdirectory(linux)
|
add_subdirectory(linux)
|
||||||
|
set(FSFW_OSAL_LINUX 1)
|
||||||
elseif(FSFW_OSAL MATCHES "host")
|
elseif(FSFW_OSAL MATCHES "host")
|
||||||
add_subdirectory(host)
|
add_subdirectory(host)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@ -13,16 +16,20 @@ elseif(FSFW_OSAL MATCHES "host")
|
|||||||
# We still need to pull in some Linux specific sources
|
# We still need to pull in some Linux specific sources
|
||||||
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
|
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
set(FSFW_OSAL_HOST 1)
|
||||||
else()
|
else()
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
||||||
|
|
||||||
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
|
||||||
# Not set. Assumuing this is a host build, try to determine host OS
|
# Not set. Assumuing this is a host build, try to determine host OS
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_subdirectory(host)
|
add_subdirectory(host)
|
||||||
add_subdirectory(windows)
|
add_subdirectory(windows)
|
||||||
|
set(FSFW_OSAL_HOST 1)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
add_subdirectory(linux)
|
add_subdirectory(linux)
|
||||||
|
set(FSFW_OSAL_LINUX 1)
|
||||||
else()
|
else()
|
||||||
# MacOS or other OSes have not been tested yet / are not supported.
|
# MacOS or other OSes have not been tested yet / are not supported.
|
||||||
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
||||||
@ -31,3 +38,5 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(common)
|
add_subdirectory(common)
|
||||||
|
|
||||||
|
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)
|
||||||
|
@ -40,6 +40,8 @@ int TcpIpBase::closeSocket(socket_t socket) {
|
|||||||
return closesocket(socket);
|
return closesocket(socket);
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
return close(socket);
|
return close(socket);
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,5 +50,7 @@ int TcpIpBase::getLastSocketError() {
|
|||||||
return WSAGetLastError();
|
return WSAGetLastError();
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
return errno;
|
return errno;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
|
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
object_id_t tcStoreId)
|
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
|
||||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
// Connection is always up, TM is requested by connecting to server and receiving packets
|
// Connection is always up, TM is requested by connecting to server and receiving packets
|
||||||
registerCommConnect();
|
registerCommConnect();
|
||||||
|
@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge {
|
|||||||
* @param tmStoreId TM store object ID. It is recommended to the default object ID
|
* @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
|
* @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 tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
virtual ~TcpTmTcBridge();
|
virtual ~TcpTmTcBridge();
|
||||||
|
@ -26,12 +26,12 @@
|
|||||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||||
size_t receptionBufferSize, size_t ringBufferSize,
|
TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize,
|
||||||
std::string customTcpServerPort, ReceptionModes receptionMode)
|
size_t ringBufferSize, ReceptionModes receptionMode)
|
||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
tmtcBridgeId(tmtcTcpBridge),
|
tmtcBridgeId(tmtcTcpBridge),
|
||||||
receptionMode(receptionMode),
|
receptionMode(receptionMode),
|
||||||
tcpConfig(std::move(customTcpServerPort)),
|
tcpConfig(cfg),
|
||||||
receptionBuffer(receptionBufferSize),
|
receptionBuffer(receptionBufferSize),
|
||||||
ringBuffer(ringBufferSize, true) {}
|
ringBuffer(ringBufferSize, true) {}
|
||||||
|
|
||||||
@ -91,6 +91,15 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tcpConfig.reuseAddr) {
|
||||||
|
unsigned int enable = 1;
|
||||||
|
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||||
|
}
|
||||||
|
if (tcpConfig.reusePort) {
|
||||||
|
unsigned int enable = 1;
|
||||||
|
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
|
||||||
|
}
|
||||||
|
|
||||||
// Bind to the address found by getaddrinfo
|
// Bind to the address found by getaddrinfo
|
||||||
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
if (retval == SOCKET_ERROR) {
|
if (retval == SOCKET_ERROR) {
|
||||||
|
@ -41,11 +41,11 @@ class SpacePacketParser;
|
|||||||
*/
|
*/
|
||||||
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
|
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
|
||||||
public:
|
public:
|
||||||
enum class ReceptionModes { SPACE_PACKETS };
|
|
||||||
|
|
||||||
struct TcpConfig {
|
struct TcpConfig {
|
||||||
public:
|
public:
|
||||||
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||||
|
TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort)
|
||||||
|
: tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passed to the recv call
|
* Passed to the recv call
|
||||||
@ -63,8 +63,23 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
*/
|
*/
|
||||||
int tcpTmFlags = 0;
|
int tcpTmFlags = 0;
|
||||||
|
|
||||||
const std::string tcpPort;
|
std::string tcpPort = DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the SO_REUSEADDR option on the socket. See
|
||||||
|
* https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is
|
||||||
|
* especially useful in a debugging and development environment where an OBSW image might be
|
||||||
|
* re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP
|
||||||
|
* port.
|
||||||
|
*/
|
||||||
|
bool reuseAddr = false;
|
||||||
|
/**
|
||||||
|
* Sets the SO_REUSEPORT option on the socket. See
|
||||||
|
* https://man7.org/linux/man-pages/man7/socket.7.html for more details.
|
||||||
|
*/
|
||||||
|
bool reusePort = false;
|
||||||
};
|
};
|
||||||
|
enum class ReceptionModes { SPACE_PACKETS };
|
||||||
|
|
||||||
static const std::string DEFAULT_SERVER_PORT;
|
static const std::string DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
@ -80,10 +95,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
* size will be the Ethernet MTU size
|
* size will be the Ethernet MTU size
|
||||||
* @param customTcpServerPort The user can specify another port than the default (7301) here.
|
* @param customTcpServerPort The user can specify another port than the default (7301) here.
|
||||||
*/
|
*/
|
||||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg,
|
||||||
size_t receptionBufferSize = RING_BUFFER_SIZE,
|
size_t receptionBufferSize = RING_BUFFER_SIZE,
|
||||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
|
||||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||||
~TcpTmTcServer() override;
|
~TcpTmTcServer() override;
|
||||||
|
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
const std::string &udpServerPort_, object_id_t tmStoreId,
|
uint32_t msgQueueDepth, const std::string &udpServerPort_,
|
||||||
object_id_t tcStoreId)
|
object_id_t tmStoreId, object_id_t tcStoreId)
|
||||||
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
||||||
if (udpServerPort_.empty()) {
|
if (udpServerPort_.empty()) {
|
||||||
udpServerPort = DEFAULT_SERVER_PORT;
|
udpServerPort = DEFAULT_SERVER_PORT;
|
||||||
} else {
|
} 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);
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||||
}
|
}
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent
|
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were sent" << std::endl;
|
||||||
<< " bytes were"
|
|
||||||
" sent."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
return returnvalue::OK;
|
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. */
|
/* The ports chosen here should not be used by any other process. */
|
||||||
static const std::string DEFAULT_SERVER_PORT;
|
static const std::string DEFAULT_SERVER_PORT;
|
||||||
|
|
||||||
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth,
|
||||||
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE,
|
||||||
object_id_t tcStoreId = objects::TC_STORE);
|
object_id_t tcStoreId = objects::TC_STORE);
|
||||||
~UdpTmTcBridge() override;
|
~UdpTmTcBridge() override;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "fsfw/tasks/FixedSlotSequence.h"
|
#include "fsfw/tasks/FixedSlotSequence.h"
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
#include "fsfw/objectmanager/ObjectManagerIF.h"
|
||||||
#include "fsfw/tasks/PeriodicTaskBase.h"
|
#include "fsfw/tasks/PeriodicTaskBase.h"
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <fsfw/returnvalues/returnvalue.h>
|
#include <fsfw/returnvalues/returnvalue.h>
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace tasks {
|
namespace tasks {
|
||||||
|
|
||||||
|
@ -76,14 +76,17 @@ timeval Clock::getUptime() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
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;
|
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_sec = uptimeSeconds;
|
||||||
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
|
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.
|
// Wait for new FSFW Clock function delivering seconds uptime.
|
||||||
|
@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs*
|
|||||||
attributes.mq_msgsize = maxMessageSize;
|
attributes.mq_msgsize = maxMessageSize;
|
||||||
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
|
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
|
||||||
// Set the name of the queue. The slash is mandatory!
|
// Set the name of the queue. The slash is mandatory!
|
||||||
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
|
sprintf(name, "/FSFW_MQ%u", queueCounter++);
|
||||||
|
|
||||||
// Create a nonblocking queue if the name is available (the queue is read
|
// Create a nonblocking queue if the name is available (the queue is read
|
||||||
// and writable for the owner as well as the group)
|
// and writable for the owner as well as the group)
|
||||||
|
36
src/fsfw/osal/osal.h.in
Normal file
36
src/fsfw/osal/osal.h.in
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace osal {
|
||||||
|
enum osalTarget{
|
||||||
|
HOST,
|
||||||
|
LINUX,
|
||||||
|
WINDOWS,
|
||||||
|
FREERTOS,
|
||||||
|
RTEMS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#cmakedefine FSFW_OSAL_HOST
|
||||||
|
#cmakedefine FSFW_OSAL_LINUX
|
||||||
|
#cmakedefine FSFW_OSAL_WINDOWS
|
||||||
|
#cmakedefine FSFW_OSAL_FREERTOS
|
||||||
|
#cmakedefine FSFW_OSAL_RTEMS
|
||||||
|
|
||||||
|
|
||||||
|
constexpr osalTarget getTarget() {
|
||||||
|
#ifdef FSFW_OSAL_HOST
|
||||||
|
return HOST;
|
||||||
|
#endif
|
||||||
|
#ifdef FSFW_OSAL_LINUX
|
||||||
|
return LINUX;
|
||||||
|
#endif
|
||||||
|
#ifdef FSFW_OSAL_WINDOWS
|
||||||
|
return WINDOWS;
|
||||||
|
#endif
|
||||||
|
#ifdef FSFW_OSAL_FREERTOS
|
||||||
|
return FREERTOS;
|
||||||
|
#endif
|
||||||
|
#ifdef FSFW_OSAL_RTEMS
|
||||||
|
return RTEMS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
@ -19,12 +19,12 @@ class CpuUsage : public SerializeIF {
|
|||||||
float timeRunning;
|
float timeRunning;
|
||||||
float percentUsage;
|
float percentUsage;
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const override;
|
Endianness streamEndianness) const override;
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const override;
|
size_t getSerializedSize() const override;
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "fsfw/osal/rtems/BinarySemaphore.h"
|
#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/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/tasks/SemaphoreFactory.h"
|
#include "fsfw/tasks/SemaphoreFactory.h"
|
||||||
|
@ -40,12 +40,14 @@ class ParameterWrapper : public SerializeIF {
|
|||||||
ParameterWrapper(Type type, uint8_t rows, uint8_t columns, const void *data);
|
ParameterWrapper(Type type, uint8_t rows, uint8_t columns, const void *data);
|
||||||
virtual ~ParameterWrapper();
|
virtual ~ParameterWrapper();
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||||
Endianness streamEndianness) const override;
|
Endianness streamEndianness) const override;
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const override;
|
size_t getSerializedSize() const override;
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||||
|
// the compiler
|
||||||
|
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||||
Endianness streamEndianness) override;
|
Endianness streamEndianness) override;
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||||
|
@ -32,7 +32,7 @@ class Fuse : public SystemObject,
|
|||||||
gp_id_t poolIdPower;
|
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.
|
//! PSS detected that current on a fuse is totally out of bounds.
|
||||||
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
static const Event FUSE_CURRENT_HIGH = MAKE_EVENT(1, severity::LOW);
|
||||||
//! PSS detected a fuse that went off.
|
//! PSS detected a fuse that went off.
|
||||||
|
@ -28,10 +28,12 @@ class PowerSwitchIF {
|
|||||||
static const ReturnValue_t SWITCH_TIMEOUT = MAKE_RETURN_CODE(2);
|
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_ON = MAKE_RETURN_CODE(3);
|
||||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
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 Event SWITCH_WENT_OFF = MAKE_EVENT(
|
|
||||||
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
|
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
|
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||||
|
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||||
/**
|
/**
|
||||||
* send a direct command to the Power Unit to enable/disable the specified switch.
|
* send a direct command to the Power Unit to enable/disable the specified switch.
|
||||||
*
|
*
|
||||||
@ -50,6 +52,7 @@ class PowerSwitchIF {
|
|||||||
* @return
|
* @return
|
||||||
* - @c SWITCH_ON if the specified switch is on.
|
* - @c SWITCH_ON if the specified switch is on.
|
||||||
* - @c SWITCH_OFF if the specified switch is off.
|
* - @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
|
* - @c returnvalue::FAILED if an error occured
|
||||||
*/
|
*/
|
||||||
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
virtual ReturnValue_t getSwitchState(power::Switch_t switchNr) const = 0;
|
||||||
|
@ -9,4 +9,4 @@ target_sources(
|
|||||||
Service17Test.cpp
|
Service17Test.cpp
|
||||||
Service20ParameterManagement.cpp
|
Service20ParameterManagement.cpp
|
||||||
CService200ModeCommanding.cpp
|
CService200ModeCommanding.cpp
|
||||||
CService201HealthCommanding.cpp)
|
CServiceHealthCommanding.cpp)
|
||||||
|
@ -19,7 +19,8 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
|
|||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservice::COMMAND_MODE_COMMAND):
|
case (Subservice::COMMAND_MODE_COMMAND):
|
||||||
case (Subservice::COMMAND_MODE_READ):
|
case (Subservice::COMMAND_MODE_READ):
|
||||||
case (Subservice::COMMAND_MODE_ANNCOUNCE):
|
case (Subservice::COMMAND_MODE_ANNOUNCE):
|
||||||
|
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
default:
|
default:
|
||||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||||
@ -53,6 +54,9 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
|
|||||||
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||||
const uint8_t *tcData, size_t tcDataLen,
|
const uint8_t *tcData, size_t tcDataLen,
|
||||||
uint32_t *state, object_id_t objectId) {
|
uint32_t *state, object_id_t objectId) {
|
||||||
|
bool recursive = false;
|
||||||
|
switch (subservice) {
|
||||||
|
case (Subservice::COMMAND_MODE_COMMAND): {
|
||||||
ModePacket modeCommandPacket;
|
ModePacket modeCommandPacket;
|
||||||
ReturnValue_t result =
|
ReturnValue_t result =
|
||||||
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||||
@ -60,9 +64,22 @@ ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND,
|
||||||
modeCommandPacket.getSubmode());
|
modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
|
||||||
return result;
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||||
|
recursive = true;
|
||||||
|
[[fallthrough]];
|
||||||
|
case (Subservice::COMMAND_MODE_ANNOUNCE):
|
||||||
|
ModeMessage::setModeAnnounceMessage(*message, recursive);
|
||||||
|
return EXECUTION_COMPLETE;
|
||||||
|
case (Subservice::COMMAND_MODE_READ):
|
||||||
|
ModeMessage::setModeReadMessage(*message);
|
||||||
|
return returnvalue::OK;
|
||||||
|
default:
|
||||||
|
return CommandingServiceBase::INVALID_SUBSERVICE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply,
|
ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply,
|
||||||
@ -73,8 +90,10 @@ ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply
|
|||||||
ReturnValue_t result = returnvalue::FAILED;
|
ReturnValue_t result = returnvalue::FAILED;
|
||||||
switch (replyId) {
|
switch (replyId) {
|
||||||
case (ModeMessage::REPLY_MODE_REPLY): {
|
case (ModeMessage::REPLY_MODE_REPLY): {
|
||||||
result = prepareModeReply(reply, objectId);
|
if (previousCommand != ModeMessage::CMD_MODE_COMMAND) {
|
||||||
break;
|
return prepareModeReply(reply, objectId);
|
||||||
|
}
|
||||||
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
case (ModeMessage::REPLY_WRONG_MODE_REPLY): {
|
case (ModeMessage::REPLY_WRONG_MODE_REPLY): {
|
||||||
result = prepareWrongModeReply(reply, objectId);
|
result = prepareWrongModeReply(reply, objectId);
|
||||||
|
@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase {
|
|||||||
COMMAND_MODE_READ = 3,
|
COMMAND_MODE_READ = 3,
|
||||||
//!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event.
|
//!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event.
|
||||||
//! This command does NOT have a reply
|
//! 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
|
//!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this
|
||||||
//! command to every child. This command does NOT have a reply.
|
//! command to every child. This command does NOT have a reply.
|
||||||
COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5,
|
COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5,
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
#include "fsfw/pus/CService201HealthCommanding.h"
|
|
||||||
|
|
||||||
#include "fsfw/health/HasHealthIF.h"
|
|
||||||
#include "fsfw/health/HealthMessage.h"
|
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
|
||||||
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
|
||||||
|
|
||||||
CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid,
|
|
||||||
uint8_t serviceId,
|
|
||||||
uint8_t numParallelCommands,
|
|
||||||
uint16_t commandTimeoutSeconds)
|
|
||||||
: CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands,
|
|
||||||
commandTimeoutSeconds) {}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
|
|
||||||
switch (subservice) {
|
|
||||||
case (Subservice::COMMAND_SET_HEALTH):
|
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
|
||||||
return returnvalue::OK;
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "Invalid Subservice" << std::endl;
|
|
||||||
#endif
|
|
||||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
|
||||||
const uint8_t *tcData,
|
|
||||||
size_t tcDataLen,
|
|
||||||
MessageQueueId_t *id,
|
|
||||||
object_id_t *objectId) {
|
|
||||||
if (tcDataLen < sizeof(object_id_t)) {
|
|
||||||
return CommandingServiceBase::INVALID_TC;
|
|
||||||
}
|
|
||||||
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
|
||||||
|
|
||||||
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
|
||||||
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
|
||||||
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
|
||||||
if (destination == nullptr) {
|
|
||||||
return CommandingServiceBase::INVALID_OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
*messageQueueToSet = destination->getCommandQueue();
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message,
|
|
||||||
uint8_t subservice, const uint8_t *tcData,
|
|
||||||
size_t tcDataLen, uint32_t *state,
|
|
||||||
object_id_t objectId) {
|
|
||||||
ReturnValue_t result = returnvalue::OK;
|
|
||||||
switch (subservice) {
|
|
||||||
case (Subservice::COMMAND_SET_HEALTH): {
|
|
||||||
HealthSetCommand healthCommand;
|
|
||||||
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
|
||||||
healthCommand.getHealth());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
|
||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
|
||||||
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// Should never happen, subservice was already checked
|
|
||||||
result = returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply,
|
|
||||||
Command_t previousCommand, uint32_t *state,
|
|
||||||
CommandMessage *optionalNextCommand,
|
|
||||||
object_id_t objectId, bool *isStep) {
|
|
||||||
Command_t replyId = reply->getCommand();
|
|
||||||
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
|
||||||
return EXECUTION_COMPLETE;
|
|
||||||
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
|
||||||
return reply->getReplyRejectedReason();
|
|
||||||
}
|
|
||||||
return CommandingServiceBase::INVALID_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not used for now, health state already reported by event
|
|
||||||
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
|
|
||||||
const CommandMessage *reply) {
|
|
||||||
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
|
||||||
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
|
||||||
HealthSetReply healthSetReply(health, oldHealth);
|
|
||||||
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
|
||||||
}
|
|
161
src/fsfw/pus/CServiceHealthCommanding.cpp
Normal file
161
src/fsfw/pus/CServiceHealthCommanding.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include <fsfw/events/EventManagerIF.h>
|
||||||
|
#include <fsfw/pus/CServiceHealthCommanding.h>
|
||||||
|
|
||||||
|
#include "fsfw/health/HasHealthIF.h"
|
||||||
|
#include "fsfw/health/HealthMessage.h"
|
||||||
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
|
#include "fsfw/pus/servicepackets/Service201Packets.h"
|
||||||
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
|
||||||
|
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
|
||||||
|
args.numParallelCommands, args.commandTimeoutSeconds),
|
||||||
|
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):
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
|
||||||
|
return returnvalue::OK;
|
||||||
|
default:
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "Invalid Subservice" << std::endl;
|
||||||
|
#endif
|
||||||
|
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice,
|
||||||
|
const uint8_t *tcData,
|
||||||
|
size_t tcDataLen,
|
||||||
|
MessageQueueId_t *id,
|
||||||
|
object_id_t *objectId) {
|
||||||
|
switch (subservice) {
|
||||||
|
case (Subservice::COMMAND_SET_HEALTH):
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||||
|
if (tcDataLen < sizeof(object_id_t)) {
|
||||||
|
return CommandingServiceBase::INVALID_TC;
|
||||||
|
}
|
||||||
|
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||||
|
|
||||||
|
return checkInterfaceAndAcquireMessageQueue(id, objectId);
|
||||||
|
}
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||||
|
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
|
||||||
|
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
|
||||||
|
if (destination == nullptr) {
|
||||||
|
return CommandingServiceBase::INVALID_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*messageQueueToSet = destination->getCommandQueue();
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||||
|
const uint8_t *tcData, size_t tcDataLen,
|
||||||
|
uint32_t *state, object_id_t objectId) {
|
||||||
|
ReturnValue_t result = returnvalue::OK;
|
||||||
|
switch (subservice) {
|
||||||
|
case (Subservice::COMMAND_SET_HEALTH): {
|
||||||
|
if (tcDataLen != sizeof(object_id_t) + sizeof(HasHealthIF::HealthState)) {
|
||||||
|
return CommandingServiceBase::INVALID_TC;
|
||||||
|
}
|
||||||
|
HealthSetCommand healthCommand;
|
||||||
|
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
|
||||||
|
healthCommand.getHealth());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
|
||||||
|
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
|
||||||
|
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||||
|
}
|
||||||
|
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
|
||||||
|
ReturnValue_t result = iterateHealthTable(true);
|
||||||
|
if (result == returnvalue::OK) {
|
||||||
|
reportAllHealth = true;
|
||||||
|
return EXECUTION_COMPLETE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// Should never happen, subservice was already checked
|
||||||
|
result = returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply,
|
||||||
|
Command_t previousCommand, uint32_t *state,
|
||||||
|
CommandMessage *optionalNextCommand,
|
||||||
|
object_id_t objectId, bool *isStep) {
|
||||||
|
Command_t replyId = reply->getCommand();
|
||||||
|
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
|
||||||
|
return EXECUTION_COMPLETE;
|
||||||
|
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
|
||||||
|
return reply->getReplyRejectedReason();
|
||||||
|
}
|
||||||
|
return CommandingServiceBase::INVALID_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CServiceHealthCommanding::doPeriodicOperation() {
|
||||||
|
if (reportAllHealth) {
|
||||||
|
for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) {
|
||||||
|
ReturnValue_t result = iterateHealthTable(false);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
reportAllHealth = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not used for now, health state already reported by event
|
||||||
|
[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply(
|
||||||
|
const CommandMessage *reply) {
|
||||||
|
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
|
||||||
|
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
|
||||||
|
HealthSetReply healthSetReply(health, oldHealth);
|
||||||
|
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
|
||||||
|
std::pair<object_id_t, HasHealthIF::HealthState> pair;
|
||||||
|
|
||||||
|
ReturnValue_t result = healthTable->iterate(&pair, reset);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second);
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,26 @@
|
|||||||
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
|
||||||
|
|
||||||
|
#include <fsfw/health/HealthTable.h>
|
||||||
|
|
||||||
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
#include "fsfw/tmtcservices/CommandingServiceBase.h"
|
||||||
|
|
||||||
|
struct HealthServiceCfg {
|
||||||
|
HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable,
|
||||||
|
uint16_t maxNumHealthInfoPerCycle)
|
||||||
|
: objectId(objectId),
|
||||||
|
apid(apid),
|
||||||
|
table(healthTable),
|
||||||
|
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
|
||||||
|
object_id_t objectId;
|
||||||
|
uint16_t apid;
|
||||||
|
object_id_t table;
|
||||||
|
uint16_t maxNumHealthInfoPerCycle;
|
||||||
|
uint8_t service = 201;
|
||||||
|
uint8_t numParallelCommands = 4;
|
||||||
|
uint16_t commandTimeoutSeconds = 60;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Custom PUS service to set health of all objects
|
* @brief Custom PUS service to set health of all objects
|
||||||
* implementing hasHealthIF.
|
* implementing hasHealthIF.
|
||||||
@ -17,11 +35,12 @@
|
|||||||
* child class like this service
|
* child class like this service
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class CService201HealthCommanding : public CommandingServiceBase {
|
class CServiceHealthCommanding : public CommandingServiceBase {
|
||||||
public:
|
public:
|
||||||
CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
|
CServiceHealthCommanding(HealthServiceCfg args);
|
||||||
uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
|
~CServiceHealthCommanding() override = default;
|
||||||
~CService201HealthCommanding() override = default;
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* CSB abstract function implementations */
|
/* CSB abstract function implementations */
|
||||||
@ -37,7 +56,14 @@ class CService201HealthCommanding : public CommandingServiceBase {
|
|||||||
CommandMessage *optionalNextCommand, object_id_t objectId,
|
CommandMessage *optionalNextCommand, object_id_t objectId,
|
||||||
bool *isStep) override;
|
bool *isStep) override;
|
||||||
|
|
||||||
|
void doPeriodicOperation() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const object_id_t healthTableId;
|
||||||
|
HealthTable *healthTable;
|
||||||
|
uint16_t maxNumHealthInfoPerCycle = 0;
|
||||||
|
bool reportAllHealth = false;
|
||||||
|
ReturnValue_t iterateHealthTable(bool reset);
|
||||||
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
|
||||||
const object_id_t *objectId);
|
const object_id_t *objectId);
|
||||||
|
|
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "fsfw/globalfunctions/CRC.h"
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
#include "fsfw/serialize/SerializeAdapter.h"
|
#include "fsfw/serialize/SerializeAdapter.h"
|
||||||
#include "fsfw/serviceinterface.h"
|
#include "fsfw/serviceinterface.h"
|
||||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
|
||||||
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
|
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
|
||||||
#include "fsfw/globalfunctions/CRC.h"
|
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||||
|
|
||||||
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
||||||
|
|
||||||
|
@ -69,14 +69,14 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
|
|||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
|
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
|
||||||
<< "MessageQueue: Can't access object" << std::endl;
|
<< "MessageQueue: Can't access object" << std::endl;
|
||||||
sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl;
|
sif::error << "Object ID: 0x" << std::hex << *objectId << std::dec << std::endl;
|
||||||
sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl;
|
sif::error << "Make sure it implements ReceivesParameterMessagesIF" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError(
|
sif::printError(
|
||||||
"Service20ParameterManagement::checkInterfaceAndAcquire"
|
"Service20ParameterManagement::checkInterfaceAndAcquire"
|
||||||
"MessageQueue: Can't access object\n");
|
"MessageQueue: Can't access object\n");
|
||||||
sif::printError("Object ID: 0x%08x\n", *objectId);
|
sif::printError("Object ID: 0x%08x\n", *objectId);
|
||||||
sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n");
|
sif::printError("Make sure it implements ReceivesParameterMessagesIF\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return CommandingServiceBase::INVALID_OBJECT;
|
return CommandingServiceBase::INVALID_OBJECT;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "fsfw/pus/Service9TimeManagement.h"
|
#include "fsfw/pus/Service9TimeManagement.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "fsfw/events/EventManagerIF.h"
|
#include "fsfw/events/EventManagerIF.h"
|
||||||
#include "fsfw/pus/servicepackets/Service9Packets.h"
|
#include "fsfw/pus/servicepackets/Service9Packets.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
@ -15,9 +17,17 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK;
|
|||||||
|
|
||||||
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
|
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case SUBSERVICE::SET_TIME: {
|
case Subservice::SET_TIME: {
|
||||||
return setTime();
|
return setTime();
|
||||||
}
|
}
|
||||||
|
case Subservice::DUMP_TIME: {
|
||||||
|
timeval newTime;
|
||||||
|
Clock::getClock_timeval(&newTime);
|
||||||
|
uint32_t subsecondMs =
|
||||||
|
static_cast<uint32_t>(std::floor(static_cast<double>(newTime.tv_usec) / 1000.0));
|
||||||
|
triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs);
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||||
}
|
}
|
||||||
@ -33,14 +43,14 @@ ReturnValue_t Service9TimeManagement::setTime() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t formerUptime;
|
timeval time;
|
||||||
Clock::getUptime(&formerUptime);
|
Clock::getClock_timeval(&time);
|
||||||
result = Clock::setClock(&timeToSet);
|
result = Clock::setClock(&timeToSet);
|
||||||
|
|
||||||
if (result == returnvalue::OK) {
|
if (result == returnvalue::OK) {
|
||||||
uint32_t newUptime;
|
timeval newTime;
|
||||||
Clock::getUptime(&newUptime);
|
Clock::getClock_timeval(&newTime);
|
||||||
triggerEvent(CLOCK_SET, newUptime, formerUptime);
|
triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec);
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
} else {
|
} else {
|
||||||
triggerEvent(CLOCK_SET_FAILURE, result, 0);
|
triggerEvent(CLOCK_SET_FAILURE, result, 0);
|
||||||
|
@ -6,10 +6,13 @@
|
|||||||
class Service9TimeManagement : public PusServiceBase {
|
class Service9TimeManagement : public PusServiceBase {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
||||||
static constexpr Event CLOCK_SET =
|
|
||||||
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
//!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds.
|
||||||
static constexpr Event CLOCK_SET_FAILURE =
|
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||||
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
|
//!< Clock dump event. P1: timeval seconds P2: timeval milliseconds.
|
||||||
|
static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO);
|
||||||
|
//!< Clock could not be set. P1: Returncode.
|
||||||
|
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW);
|
||||||
|
|
||||||
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
||||||
|
|
||||||
@ -30,8 +33,9 @@ class Service9TimeManagement : public PusServiceBase {
|
|||||||
virtual ReturnValue_t setTime();
|
virtual ReturnValue_t setTime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SUBSERVICE {
|
enum Subservice {
|
||||||
SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
|
SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
|
||||||
|
DUMP_TIME = 129,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class EventReport : public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3,
|
|||||||
parameter1(parameter1_),
|
parameter1(parameter1_),
|
||||||
parameter2(parameter2_) {}
|
parameter2(parameter2_) {}
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
SerializeIF::Endianness streamEndianness) const override {
|
SerializeIF::Endianness streamEndianness) const override {
|
||||||
ReturnValue_t result =
|
ReturnValue_t result =
|
||||||
SerializeAdapter::serialize(&reportId, buffer, size, maxSize, streamEndianness);
|
SerializeAdapter::serialize(&reportId, buffer, size, maxSize, streamEndianness);
|
||||||
@ -46,7 +46,7 @@ class EventReport : public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const override {
|
size_t getSerializedSize() const override {
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
size += SerializeAdapter::getSerializedSize(&reportId);
|
size += SerializeAdapter::getSerializedSize(&reportId);
|
||||||
size += SerializeAdapter::getSerializedSize(&objectId);
|
size += SerializeAdapter::getSerializedSize(&objectId);
|
||||||
@ -55,7 +55,7 @@ class EventReport : public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3,
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
SerializeIF::Endianness streamEndianness) override {
|
SerializeIF::Endianness streamEndianness) override {
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
// RMAP command bits
|
// RMAP command bits
|
||||||
//#define RMAP_COMMAND_BIT_INCREMENT 2
|
// #define RMAP_COMMAND_BIT_INCREMENT 2
|
||||||
//#define RMAP_COMMAND_BIT_REPLY 3
|
// #define RMAP_COMMAND_BIT_REPLY 3
|
||||||
//#define RMAP_COMMAND_BIT_WRITE 5
|
// #define RMAP_COMMAND_BIT_WRITE 5
|
||||||
//#define RMAP_COMMAND_BIT_VERIFY 4
|
// #define RMAP_COMMAND_BIT_VERIFY 4
|
||||||
//#define RMAP_COMMAND_BIT 6
|
// #define RMAP_COMMAND_BIT 6
|
||||||
|
|
||||||
namespace RMAPIds {
|
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 =
|
static const uint8_t RMAP_REPLY_WRITE =
|
||||||
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
|
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
|
||||||
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
|
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
|
||||||
//#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
|
// #define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
|
||||||
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
|
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
|
||||||
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
|
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
|
||||||
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
|
||||||
|
|
||||||
//#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
// #define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
|
||||||
//(1<<RMAP_COMMAND_BIT_REPLY))
|
//(1<<RMAP_COMMAND_BIT_REPLY))
|
||||||
//#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) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define RMAP_REPLY_READ
|
||||||
//((1<<RMAP_COMMAND_BIT_REPLY))
|
//((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_WRITE_REPLY_HEADER_LEN = 8;
|
||||||
static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12;
|
static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12;
|
||||||
static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC
|
static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC
|
||||||
//#define RMAP_COMMAND_HEADER_LEN 16
|
// #define RMAP_COMMAND_HEADER_LEN 16
|
||||||
//#define RMAP_WRITE_REPLY_HEADER_LEN 8
|
// #define RMAP_WRITE_REPLY_HEADER_LEN 8
|
||||||
//#define RMAP_READ_REPLY_HEADER_LEN 12
|
// #define RMAP_READ_REPLY_HEADER_LEN 12
|
||||||
|
|
||||||
} // namespace RMAPIds
|
} // namespace RMAPIds
|
||||||
|
|
||||||
|
@ -16,8 +16,10 @@ class SerialArrayListAdapter : public SerializeIF {
|
|||||||
public:
|
public:
|
||||||
SerialArrayListAdapter(ArrayList<T, count_t>* adaptee) : adaptee(adaptee) {}
|
SerialArrayListAdapter(ArrayList<T, count_t>* adaptee) : adaptee(adaptee) {}
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
using SerializeIF::serialize; // we overload this function as well, so this is needed to uncofuse
|
||||||
Endianness streamEndianness) const {
|
// the compiler
|
||||||
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
|
Endianness streamEndianness) const override {
|
||||||
return serialize(adaptee, buffer, size, maxSize, streamEndianness);
|
return serialize(adaptee, buffer, size, maxSize, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ class SerialArrayListAdapter : public SerializeIF {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const { return getSerializedSize(adaptee); }
|
size_t getSerializedSize() const override { return getSerializedSize(adaptee); }
|
||||||
|
|
||||||
static uint32_t getSerializedSize(const ArrayList<T, count_t>* list) {
|
static uint32_t getSerializedSize(const ArrayList<T, count_t>* list) {
|
||||||
uint32_t printSize = sizeof(count_t);
|
uint32_t printSize = sizeof(count_t);
|
||||||
@ -47,8 +49,10 @@ class SerialArrayListAdapter : public SerializeIF {
|
|||||||
return printSize;
|
return printSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
using SerializeIF::deSerialize; // we overload this function as well, so this is needed to
|
||||||
Endianness streamEndianness) {
|
// uncofuse the compiler
|
||||||
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
|
Endianness streamEndianness) override {
|
||||||
return deSerialize(adaptee, buffer, size, streamEndianness);
|
return deSerialize(adaptee, buffer, size, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,9 @@ class SerialLinkedListAdapter : public SinglyLinkedList<T>, public SerializeIF {
|
|||||||
SerialLinkedListAdapter(bool printCount = false)
|
SerialLinkedListAdapter(bool printCount = false)
|
||||||
: SinglyLinkedList<T>(), printCount(printCount) {}
|
: SinglyLinkedList<T>(), printCount(printCount) {}
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
using SerializeIF::serialize; // we overloaded this function, so this is needed to unconfuse the
|
||||||
|
// compiler
|
||||||
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const override {
|
Endianness streamEndianness) const override {
|
||||||
if (printCount) {
|
if (printCount) {
|
||||||
count_t mySize = SinglyLinkedList<T>::getSize();
|
count_t mySize = SinglyLinkedList<T>::getSize();
|
||||||
@ -68,7 +70,7 @@ class SerialLinkedListAdapter : public SinglyLinkedList<T>, public SerializeIF {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const override {
|
size_t getSerializedSize() const override {
|
||||||
if (printCount) {
|
if (printCount) {
|
||||||
return SerialLinkedListAdapter<T>::getSerializedSize() + sizeof(count_t);
|
return SerialLinkedListAdapter<T>::getSerializedSize() + sizeof(count_t);
|
||||||
} else {
|
} else {
|
||||||
@ -76,6 +78,8 @@ class SerialLinkedListAdapter : public SinglyLinkedList<T>, public SerializeIF {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using SerializeIF::deSerialize; // we overloaded this function, so this is needed to unconfuse
|
||||||
|
// the compiler
|
||||||
static size_t getSerializedSize(const LinkedElement<T>* element) {
|
static size_t getSerializedSize(const LinkedElement<T>* element) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
while (element != nullptr) {
|
while (element != nullptr) {
|
||||||
@ -85,7 +89,7 @@ class SerialLinkedListAdapter : public SinglyLinkedList<T>, public SerializeIF {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) override {
|
Endianness streamEndianness) override {
|
||||||
return deSerialize(SinglyLinkedList<T>::start, buffer, size, streamEndianness);
|
return deSerialize(SinglyLinkedList<T>::start, buffer, size, streamEndianness);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ class SerializeElement : public SerializeIF, public LinkedElement<SerializeIF> {
|
|||||||
|
|
||||||
size_t getSerializedSize() const override { return SerializeAdapter::getSerializedSize(&entry); }
|
size_t getSerializedSize() const override { return SerializeAdapter::getSerializedSize(&entry); }
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||||
Endianness streamEndianness) override {
|
Endianness streamEndianness) override {
|
||||||
return SerializeAdapter::deSerialize(&entry, buffer, size, streamEndianness);
|
return SerializeAdapter::deSerialize(&entry, buffer, size, streamEndianness);
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
|
|||||||
ReturnValue_t status = returnvalue::OK;
|
ReturnValue_t status = returnvalue::OK;
|
||||||
size_type pageSize = getSubpoolElementSize(storeId.poolIndex);
|
size_type pageSize = getSubpoolElementSize(storeId.poolIndex);
|
||||||
if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) {
|
if ((pageSize != 0) and (storeId.packetIndex < numberOfElements[storeId.poolIndex])) {
|
||||||
uint16_t packetPosition = getRawPosition(storeId);
|
size_type packetPosition = getRawPosition(storeId);
|
||||||
uint8_t* ptr = &store[storeId.poolIndex][packetPosition];
|
uint8_t* ptr = &store[storeId.poolIndex][packetPosition];
|
||||||
std::memset(ptr, 0, pageSize);
|
std::memset(ptr, 0, pageSize);
|
||||||
// Set free list
|
// Set free list
|
||||||
|
@ -15,8 +15,8 @@ class ModeListEntry : public SerializeIF, public LinkedElement<ModeListEntry> {
|
|||||||
uint8_t value3 = 0;
|
uint8_t value3 = 0;
|
||||||
uint8_t value4 = 0;
|
uint8_t value4 = 0;
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const {
|
Endianness streamEndianness) const override {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
|
|
||||||
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
|
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
|
||||||
@ -40,12 +40,12 @@ class ModeListEntry : public SerializeIF, public LinkedElement<ModeListEntry> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
size_t getSerializedSize() const override {
|
||||||
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
|
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||||
Endianness streamEndianness) {
|
Endianness streamEndianness) override {
|
||||||
ReturnValue_t result;
|
ReturnValue_t result;
|
||||||
|
|
||||||
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness);
|
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness);
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
|
|
||||||
|
CdsShortTimeStamper::CdsShortTimeStamper() : SystemObject(0, false) {}
|
||||||
|
|
||||||
CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {}
|
CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {}
|
||||||
|
|
||||||
ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
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 {
|
class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t TIMESTAMP_LEN = 7;
|
static constexpr size_t TIMESTAMP_LEN = 7;
|
||||||
|
CdsShortTimeStamper();
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor which also registers the time stamper as a
|
* @brief Default constructor which also registers the time stamper as a
|
||||||
* system object so it can be found with the #objectManager.
|
* system object so it can be found with the #objectManager.
|
||||||
|
@ -100,5 +100,6 @@ ReturnValue_t PusTcCreator::setSerializableUserData(const SerializeIF &serializa
|
|||||||
void PusTcCreator::setup() {
|
void PusTcCreator::setup() {
|
||||||
spCreator.setPacketType(ccsds::PacketType::TC);
|
spCreator.setPacketType(ccsds::PacketType::TC);
|
||||||
spCreator.setSecHeaderFlag();
|
spCreator.setSecHeaderFlag();
|
||||||
|
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
|
||||||
updateSpLengthField();
|
updateSpLengthField();
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,7 @@ void PusTmCreator::setup() {
|
|||||||
updateSpLengthField();
|
updateSpLengthField();
|
||||||
spCreator.setPacketType(ccsds::PacketType::TM);
|
spCreator.setPacketType(ccsds::PacketType::TM);
|
||||||
spCreator.setSecHeaderFlag();
|
spCreator.setSecHeaderFlag();
|
||||||
|
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) {
|
void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) {
|
||||||
|
@ -40,7 +40,7 @@ struct PusTmParams {
|
|||||||
size_t dataLen)
|
size_t dataLen)
|
||||||
: secHeader(service, subservice, timeStamper), adapter(data, dataLen), sourceData(&adapter) {}
|
: secHeader(service, subservice, timeStamper), adapter(data, dataLen), sourceData(&adapter) {}
|
||||||
PusTmSecHeader secHeader;
|
PusTmSecHeader secHeader;
|
||||||
SerialBufferAdapter<uint8_t> adapter;
|
SerialBufferAdapter<size_t> adapter;
|
||||||
const SerializeIF* sourceData = nullptr;
|
const SerializeIF* sourceData = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define TMTCBRIDGE_WIRETAPPING 0
|
#define TMTCBRIDGE_WIRETAPPING 0
|
||||||
|
|
||||||
TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
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),
|
: SystemObject(objectId),
|
||||||
name(name),
|
name(name),
|
||||||
tmStoreId(tmStoreId),
|
tmStoreId(tmStoreId),
|
||||||
@ -16,7 +16,9 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
|
|||||||
tcDestination(tcDestination)
|
tcDestination(tcDestination)
|
||||||
|
|
||||||
{
|
{
|
||||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
|
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||||
|
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
|
msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||||
@ -35,7 +37,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) {
|
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
|
||||||
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
|
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
|
||||||
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
|
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
@ -143,13 +145,17 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
|
|||||||
#endif /* FSFW_VERBOSE_LEVEL >= 3 */
|
#endif /* FSFW_VERBOSE_LEVEL >= 3 */
|
||||||
|
|
||||||
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) {
|
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) {
|
||||||
storeDownlinkData(&message);
|
ReturnValue_t result = storeDownlinkData(&message);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
tmStore->deleteData(message.getStorageId());
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = tmStore->getData(message.getStorageId(), &data, &size);
|
result = tmStore->getData(message.getStorageId(), &data, &size);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
status = result;
|
status = result;
|
||||||
|
tmStore->deleteData(message.getStorageId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,9 +163,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
|
|||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
status = result;
|
status = result;
|
||||||
} else {
|
} else {
|
||||||
tmStore->deleteData(message.getStorageId());
|
|
||||||
packetSentCounter++;
|
packetSentCounter++;
|
||||||
}
|
}
|
||||||
|
tmStore->deleteData(message.getStorageId());
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -171,6 +177,7 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tmFifo->full()) {
|
if (tmFifo->full()) {
|
||||||
|
if (warningSwitch) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||||
"of stored packet IDs reached!"
|
"of stored packet IDs reached!"
|
||||||
@ -180,6 +187,8 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
|
|||||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||||
"of stored packet IDs reached!\n");
|
"of stored packet IDs reached!\n");
|
||||||
#endif
|
#endif
|
||||||
|
warningSwitch = false;
|
||||||
|
}
|
||||||
if (overwriteOld) {
|
if (overwriteOld) {
|
||||||
tmFifo->retrieve(&storeId);
|
tmFifo->retrieve(&storeId);
|
||||||
tmStore->deleteData(storeId);
|
tmStore->deleteData(storeId);
|
||||||
@ -221,6 +230,7 @@ ReturnValue_t TmTcBridge::handleStoredTm() {
|
|||||||
packetSentCounter++;
|
packetSentCounter++;
|
||||||
|
|
||||||
if (tmFifo->empty()) {
|
if (tmFifo->empty()) {
|
||||||
|
warningSwitch = true;
|
||||||
tmStored = false;
|
tmStored = false;
|
||||||
}
|
}
|
||||||
tmStore->deleteData(storeId);
|
tmStore->deleteData(storeId);
|
||||||
|
@ -15,15 +15,14 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
|||||||
public ExecutableObjectIF,
|
public ExecutableObjectIF,
|
||||||
public SystemObject {
|
public SystemObject {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
|
|
||||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||||
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200;
|
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_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||||
|
|
||||||
TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination,
|
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;
|
~TmTcBridge() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +41,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
|||||||
* @return -@c returnvalue::OK if value was set successfully
|
* @return -@c returnvalue::OK if value was set successfully
|
||||||
* -@c returnvalue::FAILED otherwise, stored value stays the same
|
* -@c returnvalue::FAILED otherwise, stored value stays the same
|
||||||
*/
|
*/
|
||||||
ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
|
ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will set up the bridge to overwrite old data in the FIFO.
|
* This will set up the bridge to overwrite old data in the FIFO.
|
||||||
@ -91,6 +90,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
|||||||
//! by default, so telemetry will be handled immediately.
|
//! by default, so telemetry will be handled immediately.
|
||||||
bool communicationLinkUp = true;
|
bool communicationLinkUp = true;
|
||||||
bool tmStored = false;
|
bool tmStored = false;
|
||||||
|
bool warningSwitch = true;
|
||||||
bool overwriteOld = true;
|
bool overwriteOld = true;
|
||||||
uint8_t packetSentCounter = 0;
|
uint8_t packetSentCounter = 0;
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
|||||||
*/
|
*/
|
||||||
DynamicFIFO<store_address_t>* tmFifo = nullptr;
|
DynamicFIFO<store_address_t>* tmFifo = nullptr;
|
||||||
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
||||||
uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */
|
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "fsfw/FSFWVersion.h"
|
#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 {
|
void fsfw::Version::getVersion(char* str, size_t maxLen) const {
|
||||||
size_t len = snprintf(str, maxLen, "%d.%d.%d", major, minor, revision);
|
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);
|
snprintf(str + len, maxLen - len, "-%s", addInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,7 +31,7 @@ namespace fsfw {
|
|||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
std::ostream& operator<<(std::ostream& os, const Version& v) {
|
||||||
os << v.major << "." << v.minor << "." << v.revision;
|
os << v.major << "." << v.minor << "." << v.revision;
|
||||||
if (v.addInfo != nullptr) {
|
if (v.addInfo != nullptr and std::strcmp(v.addInfo, "") != 0) {
|
||||||
os << "-" << v.addInfo;
|
os << "-" << v.addInfo;
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
|
@ -325,12 +325,12 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
|||||||
// trickery here to calculate the raw values first
|
// trickery here to calculate the raw values first
|
||||||
int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8;
|
int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8;
|
||||||
int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8;
|
int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8;
|
||||||
int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8;
|
int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[9] << 8)) >> 8;
|
||||||
|
|
||||||
// Now scale to physical value in microtesla
|
// Now scale to physical value in microtesla
|
||||||
float fieldStrengthX = fieldStrengthRawX * scaleFactorX;
|
float fieldStrengthX = fieldStrengthRawX * scaleFactorX;
|
||||||
float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
|
float fieldStrengthY = fieldStrengthRawY * scaleFactorY;
|
||||||
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
|
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorZ;
|
||||||
|
|
||||||
if (periodicPrintout) {
|
if (periodicPrintout) {
|
||||||
if (debugDivider.checkAndIncrement()) {
|
if (debugDivider.checkAndIncrement()) {
|
||||||
|
@ -180,10 +180,6 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
|
|
||||||
<< " bytes" << std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
void Factory::produceFrameworkObjects(void* args) {
|
void Factory::produceFrameworkObjects(void* args) {
|
||||||
setStaticFrameworkObjectIds();
|
setStaticFrameworkObjectIds();
|
||||||
new EventManager(objects::EVENT_MANAGER);
|
new EventManager(objects::EVENT_MANAGER, 80);
|
||||||
new HealthTable(objects::HEALTH_TABLE);
|
new HealthTable(objects::HEALTH_TABLE);
|
||||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
|
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
|
||||||
|
|
||||||
|
@ -31,4 +31,7 @@ int customSetup() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int customTeardown() { return 0; }
|
int customTeardown() {
|
||||||
|
ObjectManager::clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -27,12 +27,7 @@ TEST_CASE("Action Helper", "[action]") {
|
|||||||
CHECK(not testDhMock.executeActionCalled);
|
CHECK(not testDhMock.executeActionCalled);
|
||||||
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == returnvalue::OK);
|
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == returnvalue::OK);
|
||||||
CHECK(testDhMock.executeActionCalled);
|
CHECK(testDhMock.executeActionCalled);
|
||||||
// No message is sent if everything is alright.
|
|
||||||
CHECK(not testMqMock.wasMessageSent());
|
CHECK(not testMqMock.wasMessageSent());
|
||||||
store_address_t invalidAddress;
|
|
||||||
ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress);
|
|
||||||
actionHelper.handleActionMessage(&actionMessage);
|
|
||||||
CHECK(testMqMock.wasMessageSent());
|
|
||||||
const uint8_t* ptr = nullptr;
|
const uint8_t* ptr = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) ==
|
REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) ==
|
||||||
@ -44,6 +39,10 @@ TEST_CASE("Action Helper", "[action]") {
|
|||||||
for (uint8_t i = 0; i < 3; i++) {
|
for (uint8_t i = 0; i < 3; i++) {
|
||||||
REQUIRE(ptr[i] == (i + 1));
|
REQUIRE(ptr[i] == (i + 1));
|
||||||
}
|
}
|
||||||
|
// Action message without application data is also valid
|
||||||
|
store_address_t invalidAddress;
|
||||||
|
ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress);
|
||||||
|
actionHelper.handleActionMessage(&actionMessage);
|
||||||
testDhMock.clearBuffer();
|
testDhMock.clearBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,17 +94,5 @@ TEST_CASE("Action Helper", "[action]") {
|
|||||||
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Missing IPC Data") {
|
|
||||||
ActionMessage::setCommand(&actionMessage, testActionId, store_address_t::invalid());
|
|
||||||
CHECK(not testDhMock.executeActionCalled);
|
|
||||||
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == returnvalue::OK);
|
|
||||||
CommandMessage testMessage;
|
|
||||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
|
||||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
|
||||||
REQUIRE(ActionMessage::getReturnCode(&testMessage) ==
|
|
||||||
static_cast<uint32_t>(StorageManagerIF::ILLEGAL_STORAGE_ID));
|
|
||||||
REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Data Reply") {}
|
SECTION("Data Reply") {}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
target_sources(
|
target_sources(${FSFW_TEST_TGT} PRIVATE testDistributor.cpp
|
||||||
${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp
|
testFaultHandler.cpp)
|
||||||
testSourceHandler.cpp testFaultHandler.cpp)
|
|
||||||
|
@ -1,244 +0,0 @@
|
|||||||
#include <etl/crc32.h>
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
#include <random>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "fsfw/cfdp.h"
|
|
||||||
#include "fsfw/cfdp/pdu/EofPduCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/FileDataCreator.h"
|
|
||||||
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
|
|
||||||
#include "mocks/AcceptsTmMock.h"
|
|
||||||
#include "mocks/EventReportingProxyMock.h"
|
|
||||||
#include "mocks/FilesystemMock.h"
|
|
||||||
#include "mocks/MessageQueueMock.h"
|
|
||||||
#include "mocks/StorageManagerMock.h"
|
|
||||||
#include "mocks/cfdp/FaultHandlerMock.h"
|
|
||||||
#include "mocks/cfdp/RemoteConfigTableMock.h"
|
|
||||||
#include "mocks/cfdp/UserMock.h"
|
|
||||||
|
|
||||||
TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
|
||||||
using namespace cfdp;
|
|
||||||
using namespace returnvalue;
|
|
||||||
MessageQueueId_t destQueueId = 2;
|
|
||||||
AcceptsTmMock tmReceiver(destQueueId);
|
|
||||||
MessageQueueMock mqMock(destQueueId);
|
|
||||||
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2));
|
|
||||||
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(3));
|
|
||||||
FaultHandlerMock fhMock;
|
|
||||||
LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock);
|
|
||||||
FilesystemMock fsMock;
|
|
||||||
UserMock userMock(fsMock);
|
|
||||||
RemoteConfigTableMock remoteCfgTableMock;
|
|
||||||
PacketInfoList<64> packetInfoList;
|
|
||||||
LostSegmentsList<128> lostSegmentsList;
|
|
||||||
DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList,
|
|
||||||
lostSegmentsList);
|
|
||||||
EventReportingProxyMock eventReporterMock;
|
|
||||||
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
|
|
||||||
StorageManagerMock tcStore(2, storeCfg);
|
|
||||||
StorageManagerMock tmStore(3, storeCfg);
|
|
||||||
FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock);
|
|
||||||
RemoteEntityCfg cfg(remoteId);
|
|
||||||
remoteCfgTableMock.addRemoteConfig(cfg);
|
|
||||||
fp.tcStore = &tcStore;
|
|
||||||
fp.tmStore = &tmStore;
|
|
||||||
uint8_t* buf = nullptr;
|
|
||||||
size_t serLen = 0;
|
|
||||||
store_address_t storeId;
|
|
||||||
PduConfig conf;
|
|
||||||
auto destHandler = DestHandler(dp, fp);
|
|
||||||
CHECK(destHandler.initialize() == OK);
|
|
||||||
|
|
||||||
auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) {
|
|
||||||
std::string srcNameString = "hello.txt";
|
|
||||||
std::string destNameString = "hello-cpy.txt";
|
|
||||||
StringLv srcName(srcNameString);
|
|
||||||
StringLv destName(destNameString);
|
|
||||||
MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName);
|
|
||||||
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
|
|
||||||
conf.sourceId = remoteId;
|
|
||||||
conf.destId = localId;
|
|
||||||
conf.mode = TransmissionMode::UNACKNOWLEDGED;
|
|
||||||
conf.seqNum = seqNum;
|
|
||||||
MetadataPduCreator metadataCreator(conf, info);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(metadataCreator.getPduType(), storeId,
|
|
||||||
metadataCreator.getDirectiveCode());
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName,
|
|
||||||
const char* destName, size_t fileLen) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AGAIN);
|
|
||||||
REQUIRE(res.errors == 0);
|
|
||||||
// Assert that the packet was deleted after handling
|
|
||||||
REQUIRE(not tcStore.hasDataAtId(storeId));
|
|
||||||
REQUIRE(packetInfoList.empty());
|
|
||||||
REQUIRE(userMock.metadataRecvd.size() == 1);
|
|
||||||
auto& idMetadataPair = userMock.metadataRecvd.back();
|
|
||||||
REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
|
|
||||||
REQUIRE(idMetadataPair.second.sourceId.getValue() == 3);
|
|
||||||
REQUIRE(idMetadataPair.second.fileSize == fileLen);
|
|
||||||
REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0);
|
|
||||||
REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0);
|
|
||||||
userMock.metadataRecvd.pop();
|
|
||||||
REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end());
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) {
|
|
||||||
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize));
|
|
||||||
EofPduCreator eofCreator(conf, eofInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode());
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::IDLE);
|
|
||||||
REQUIRE(res.errors == 0);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::IDLE);
|
|
||||||
// Assert that the packet was deleted after handling
|
|
||||||
REQUIRE(not tcStore.hasDataAtId(storeId));
|
|
||||||
REQUIRE(packetInfoList.empty());
|
|
||||||
REQUIRE(userMock.eofsRevd.size() == 1);
|
|
||||||
auto& eofId = userMock.eofsRevd.back();
|
|
||||||
CHECK(eofId == id);
|
|
||||||
REQUIRE(userMock.finishedRecvd.size() == 1);
|
|
||||||
auto& idParamPair = userMock.finishedRecvd.back();
|
|
||||||
CHECK(idParamPair.first == id);
|
|
||||||
CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR);
|
|
||||||
};
|
|
||||||
|
|
||||||
auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res,
|
|
||||||
const std::vector<store_address_t>& idsToCheck) {
|
|
||||||
REQUIRE(res.result == OK);
|
|
||||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
|
||||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
|
||||||
for (const auto id : idsToCheck) {
|
|
||||||
REQUIRE(not tcStore.hasDataAtId(id));
|
|
||||||
}
|
|
||||||
REQUIRE(packetInfoList.empty());
|
|
||||||
};
|
|
||||||
|
|
||||||
SECTION("State") {
|
|
||||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
|
||||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Idle State Machine Iteration") {
|
|
||||||
auto res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
CHECK(res.errors == 0);
|
|
||||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
|
||||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Empty File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
FileSize cfdpFileSize(0);
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
eofPreparation(cfdpFileSize, 0);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Small File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
std::string fileData = "hello test data";
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
crcCalc.add(fileData.begin(), fileData.end());
|
|
||||||
uint32_t crc32 = crcCalc.value();
|
|
||||||
FileSize cfdpFileSize(fileData.size());
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
FileSize offset(0);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
|
|
||||||
fileData.size());
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
fileDataPduCheck(res, {storeId});
|
|
||||||
eofPreparation(cfdpFileSize, crc32);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Segmented File Transfer") {
|
|
||||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
|
||||||
CHECK(res.result == OK);
|
|
||||||
std::random_device dev;
|
|
||||||
std::mt19937 rng(dev());
|
|
||||||
std::uniform_int_distribution<std::mt19937::result_type> distU8(0, 255);
|
|
||||||
std::array<uint8_t, 1024> largerFileData{};
|
|
||||||
for (auto& val : largerFileData) {
|
|
||||||
val = distU8(rng);
|
|
||||||
}
|
|
||||||
etl::crc32 crcCalc;
|
|
||||||
crcCalc.add(largerFileData.begin(), largerFileData.end());
|
|
||||||
uint32_t crc32 = crcCalc.value();
|
|
||||||
FileSize cfdpFileSize(largerFileData.size());
|
|
||||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
|
||||||
auto transactionId = destHandler.getTransactionId();
|
|
||||||
|
|
||||||
std::vector<store_address_t> idsToCheck;
|
|
||||||
{
|
|
||||||
FileSize offset(0);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()),
|
|
||||||
largerFileData.size() / 2);
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
idsToCheck.push_back(storeId);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
FileSize offset(512);
|
|
||||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512),
|
|
||||||
largerFileData.size() / 2);
|
|
||||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
|
||||||
REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK);
|
|
||||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
|
||||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
|
||||||
idsToCheck.push_back(storeId);
|
|
||||||
packetInfoList.push_back(packetInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
fileDataPduCheck(res, idsToCheck);
|
|
||||||
eofPreparation(cfdpFileSize, crc32);
|
|
||||||
// After EOF, operation is done because no closure was requested
|
|
||||||
destHandler.performStateMachine();
|
|
||||||
eofCheck(res, transactionId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
TEST_CASE("CFDP Source Handler", "[cfdp]") {}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user