Compare commits
33 Commits
develop_up
...
docker_d8
Author | SHA1 | Date | |
---|---|---|---|
efc2773f84 | |||
87bb29a66a | |||
45963b2064 | |||
bc312243df | |||
9589d702dd | |||
c66fab90f9 | |||
3e8446ba8b | |||
e37af4fe70 | |||
941bf61f28 | |||
70fd9ff3e5 | |||
81c5b2ec95 | |||
7426e10f82 | |||
123c81777a | |||
dcc28622a5 | |||
6d85fa155e | |||
e6af6200ae | |||
5ca3e83934 | |||
6adabb059a | |||
5d0a5cd201 | |||
adb8483bb0 | |||
fdfdce2fb0 | |||
90efb132d0 | |||
fe9804d922 | |||
a0eae66c35 | |||
e131480d5f | |||
90bafbb6de | |||
47d85fb61c | |||
39dad5f45b | |||
a993c4e0d4 | |||
fe9cc20d00 | |||
552a12a6ad | |||
13639feec6 | |||
654de0f586 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "automation/msvc-wine"]
|
||||||
|
path = automation/msvc-wine
|
||||||
|
url = https://github.com/mstorsjo/msvc-wine
|
||||||
|
8
.idea/cmake.xml
generated
8
.idea/cmake.xml
generated
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CMakeSharedSettings">
|
|
||||||
<configurations>
|
|
||||||
<configuration PROFILE_NAME="Debug Test" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DFSFW_BUILD_TESTS=ON -DFSFW_OSAL=host" />
|
|
||||||
</configurations>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
167
CHANGELOG.md
167
CHANGELOG.md
@ -8,72 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
## Fixes
|
# [v6.0.0]
|
||||||
|
|
||||||
- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source
|
|
||||||
data with a size limited only by the size of `size_t`.
|
|
||||||
- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence
|
|
||||||
number fields stored the actual length of the field instead of the length minus 1 like specified
|
|
||||||
in the CFDP standard.
|
|
||||||
- PUS Health Service: Size check for set health command.
|
|
||||||
Perform operation completion for announce health command.
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746
|
|
||||||
- Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime.
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745
|
|
||||||
- Small tweak for version getter
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/744
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- add CFDP subsystem ID
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
|
||||||
- `PusTmZcWriter` now exposes API to set message counter field.
|
|
||||||
|
|
||||||
## Changed
|
|
||||||
|
|
||||||
- HK generation is now countdown based.
|
|
||||||
- Bump ETL version to 20.35.14
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748
|
|
||||||
- Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`.
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
|
||||||
- Add new `PowerSwitchIF::SWITCH_UNKNOWN` returnvalue.
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743
|
|
||||||
- Assert that `FixedArrayList` is larger than 0 at compile time.
|
|
||||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740
|
|
||||||
- Health functions are virtual now.
|
|
||||||
|
|
||||||
# [v6.0.0] 2023-02-10
|
|
||||||
|
|
||||||
## Fixes
|
## 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
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
|
||||||
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
|
- 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
|
||||||
@ -83,84 +25,22 @@ 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
|
||||||
|
|
||||||
- `CServiceHealthCommanding`: Add announce all health info implementation
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122
|
|
||||||
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
|
|
||||||
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
|
||||||
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
|
|
||||||
option on the TCP server. CTOR prototype has changed and expects an explicit
|
|
||||||
TCP configuration struct to be passed.
|
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
|
|
||||||
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
- `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
|
||||||
so they can be used without template specification.
|
to 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
|
||||||
@ -190,41 +70,18 @@ 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
|
||||||
- Generic TMTC Bridge Update
|
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734
|
interface itself so it can be re-used more easily. Also add new
|
||||||
- comment tweak to event parser can read everything
|
abstract function `bool hasDataAtId(store_address_t storeId) const`.
|
||||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732
|
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
|
||||||
- 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
|
||||||
|
|
||||||
@ -244,7 +101,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] 2022-07-25
|
# [v5.0.0] 25.07.2022
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
|
|||||||
# Version file handling #
|
# Version file handling #
|
||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
|
|
||||||
set(FSFW_VERSION_IF_GIT_FAILS 6)
|
set(FSFW_VERSION_IF_GIT_FAILS 5)
|
||||||
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)
|
||||||
|
|
||||||
@ -64,6 +64,12 @@ elseif(${CMAKE_CXX_STANDARD} LESS 17)
|
|||||||
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
"${MSG_PREFIX} Compiling the FSFW requires a minimum of C++17 support")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
|
# Manually tweak MSVC to emit (about) the same warnings as clang and gcc on linux
|
||||||
|
add_compile_options("/permissive-" /wd4267 /wd4244 /wd4244 /wd4305 /wd4805 /wd4267 /wd4646 /wd4065 /Dand=&& /Dor=|| /Dnot=!)
|
||||||
|
add_compile_definitions(NOMINMAX)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
set(FSFW_SOURCES_DIR "${CMAKE_SOURCE_DIR}/src/fsfw")
|
||||||
|
|
||||||
set(FSFW_ETL_LIB_NAME etl)
|
set(FSFW_ETL_LIB_NAME etl)
|
||||||
@ -72,7 +78,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}.35.14
|
${FSFW_ETL_LIB_MAJOR_VERSION}.28.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)
|
||||||
|
|
||||||
@ -158,7 +164,7 @@ if(FSFW_BUILD_TESTS)
|
|||||||
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)
|
||||||
|
|
||||||
@ -174,6 +180,27 @@ if(FSFW_BUILD_TESTS)
|
|||||||
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
|
||||||
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
|
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
|
||||||
|
|
||||||
|
if(FSFW_OSAL MATCHES "freertos")
|
||||||
|
message(STATUS "${MSG_PREFIX} Downloading FreeRTOS with FetchContent")
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
set(FreeRTOS_PORT posix)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
FreeRTOS
|
||||||
|
GIT_REPOSITORY https://egit.irs.uni-stuttgart.de/fsfw/FreeRTOS-LTS
|
||||||
|
GIT_TAG develop
|
||||||
|
GIT_SUBMODULES FreeRTOS/FreeRTOS-Kernel)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(FreeRTOS)
|
||||||
|
|
||||||
|
set(LIB_OS_NAME FreeRTOS)
|
||||||
|
target_include_directories(FreeRTOS PUBLIC unittests/testcfg/freertos)
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
target_link_libraries(FreeRTOS PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
endif()
|
||||||
|
|
||||||
project(${FSFW_TEST_TGT} CXX C)
|
project(${FSFW_TEST_TGT} CXX C)
|
||||||
add_executable(${FSFW_TEST_TGT})
|
add_executable(${FSFW_TEST_TGT})
|
||||||
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
|
||||||
@ -201,8 +228,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} ETL installation not found. Downloading ETL with FetchContent."
|
"${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
|
||||||
)
|
"etl with FindPackage")
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
@ -226,6 +253,7 @@ if(FSFW_FETCH_CONTENT_TARGETS)
|
|||||||
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
|
||||||
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(FSFW_CORE_INC_PATH "inc")
|
set(FSFW_CORE_INC_PATH "inc")
|
||||||
@ -360,6 +388,9 @@ if(FSFW_BUILD_TESTS)
|
|||||||
endif()
|
endif()
|
||||||
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
|
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
|
||||||
${LIB_FSFW_NAME})
|
${LIB_FSFW_NAME})
|
||||||
|
if(FSFW_OSAL MATCHES "freertos")
|
||||||
|
target_link_libraries(${FSFW_TEST_TGT} PRIVATE FreeRTOS)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If
|
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If
|
||||||
@ -447,8 +478,8 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
set(COMPILER_FLAGS "/permissive-")
|
set(FSFW_WARNING_FLAGS -Wall -Wno-gnu-anonymous-struct)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Required include paths to compile the FSFW
|
# Required include paths to compile the FSFW
|
||||||
|
@ -5,7 +5,7 @@ RUN apt-get --yes upgrade
|
|||||||
|
|
||||||
#tzdata is a dependency, won't install otherwise
|
#tzdata is a dependency, won't install otherwise
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync
|
RUN apt-get --yes install ca-certificates clang cmake doxygen g++ gcc git graphviz iputils-ping lcov make msitools nano ninja-build pip python3 python3-simplejson python3-six qemu-system-arm rsync valgrind wget winbind wine64-development
|
||||||
|
|
||||||
RUN python3 -m pip install sphinx breathe
|
RUN python3 -m pip install sphinx breathe
|
||||||
|
|
||||||
@ -21,8 +21,27 @@ RUN git clone https://github.com/ETLCPP/etl.git && \
|
|||||||
cmake -B build . && \
|
cmake -B build . && \
|
||||||
cmake --install build/
|
cmake --install build/
|
||||||
|
|
||||||
|
|
||||||
|
# install our own rtems build
|
||||||
|
RUN wget -qO- https://buggy.irs.uni-stuttgart.de/rtems_releases/rtems6-12.2.1.tar.bz2 | tar -xj -C /opt/
|
||||||
|
ENV PATH="$PATH:/opt/rtems/6/bin"
|
||||||
|
|
||||||
|
|
||||||
|
# install msvc using https://github.com/mstorsjo/msvc-wine
|
||||||
|
# see msvc-wine/LICENSE.txt
|
||||||
|
COPY msvc-wine/lowercase msvc-wine/fixinclude msvc-wine/install.sh msvc-wine/vsdownload.py ./
|
||||||
|
COPY msvc-wine/wrappers/* ./wrappers/
|
||||||
|
RUN PYTHONUNBUFFERED=1 ./vsdownload.py --accept-license --dest /opt/msvc && \
|
||||||
|
./install.sh /opt/msvc && \
|
||||||
|
rm lowercase fixinclude install.sh vsdownload.py && \
|
||||||
|
rm -rf wrappers
|
||||||
|
COPY msvc-wine/msvcenv-native.sh /opt/msvc
|
||||||
|
RUN wine64 wineboot --init && \
|
||||||
|
while pgrep wineserver > /dev/null; do sleep 1; done
|
||||||
|
|
||||||
|
|
||||||
#ssh needs a valid user to work
|
#ssh needs a valid user to work
|
||||||
RUN adduser --uid 114 jenkins
|
RUN adduser -q --uid 114 jenkins
|
||||||
|
|
||||||
#add documentation server to known hosts
|
#add documentation server to known hosts
|
||||||
RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts
|
||||||
|
105
automation/Jenkinsfile
vendored
105
automation/Jenkinsfile
vendored
@ -2,86 +2,61 @@ pipeline {
|
|||||||
environment {
|
environment {
|
||||||
BUILDDIR_HOST = 'cmake-build-tests-host'
|
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||||
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||||
|
BUILDDIR_FREERTOS = 'cmake-build-tests-freertos'
|
||||||
|
BUILDDIR_RTEMS = 'cmake-build-tests-rtems'
|
||||||
DOCDDIR = 'cmake-build-documentation'
|
DOCDDIR = 'cmake-build-documentation'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
image 'fsfw-ci:d6'
|
image 'fsfw-ci:d7'
|
||||||
args '--network host --sysctl fs.mqueue.msg_max=100'
|
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('Host') {
|
stage('Host') {
|
||||||
stages{
|
steps {
|
||||||
stage('Clean') {
|
sh 'rm -rf $BUILDDIR_HOST'
|
||||||
steps {
|
|
||||||
sh 'rm -rf $BUILDDIR_HOST'
|
dir(BUILDDIR_HOST) {
|
||||||
}
|
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
}
|
sh 'cmake --build . -j4'
|
||||||
stage('Configure') {
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
steps {
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
dir(BUILDDIR_HOST) {
|
|
||||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Build') {
|
|
||||||
steps {
|
|
||||||
dir(BUILDDIR_HOST) {
|
|
||||||
sh 'cmake --build . -j4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Unittests') {
|
|
||||||
steps {
|
|
||||||
dir(BUILDDIR_HOST) {
|
|
||||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Valgrind') {
|
|
||||||
steps {
|
|
||||||
dir(BUILDDIR_HOST) {
|
|
||||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('Linux') {
|
stage('Linux') {
|
||||||
stages{
|
steps {
|
||||||
stage('Clean') {
|
sh 'rm -rf $BUILDDIR_LINUX'
|
||||||
steps {
|
|
||||||
sh 'rm -rf $BUILDDIR_LINUX'
|
dir(BUILDDIR_LINUX) {
|
||||||
}
|
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
|
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
}
|
}
|
||||||
stage('Configure') {
|
}
|
||||||
steps {
|
}
|
||||||
dir(BUILDDIR_LINUX) {
|
stage('FreeRTOS') {
|
||||||
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
steps {
|
||||||
}
|
sh 'rm -rf $BUILDDIR_FREERTOS'
|
||||||
}
|
|
||||||
|
dir(BUILDDIR_FREERTOS) {
|
||||||
|
sh 'cmake -DFSFW_OSAL=freertos -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||||
|
sh 'cmake --build . -j4'
|
||||||
|
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||||
|
//sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||||
}
|
}
|
||||||
stage('Build') {
|
}
|
||||||
steps {
|
}
|
||||||
dir(BUILDDIR_LINUX) {
|
stage('rtems') {
|
||||||
sh 'cmake --build . -j4'
|
steps {
|
||||||
}
|
sh 'rm -rf $BUILDDIR_RTEMS'
|
||||||
}
|
|
||||||
}
|
dir(BUILDDIR_RTEMS) {
|
||||||
stage('Unittests') {
|
sh 'cmake -DFSFW_OSAL=rtems -DFSFW_BUILD_TESTS=ON -DFSFW_TESTS_GEN_COV=OFF -DFSFW_CICD_BUILD=ON -DCMAKE_TOOLCHAIN_FILE=../unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake ..'
|
||||||
steps {
|
sh 'cmake --build . -j4'
|
||||||
dir(BUILDDIR_LINUX) {
|
sh 'qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio -semihosting -machine virt,gic-version=3 -cpu cortex-a72 -m 4000 -kernel fsfw-tests'
|
||||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Valgrind') {
|
|
||||||
steps {
|
|
||||||
dir(BUILDDIR_LINUX) {
|
|
||||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
automation/msvc-wine
Submodule
1
automation/msvc-wine
Submodule
Submodule automation/msvc-wine added at 2d2d7db0b5
@ -51,10 +51,7 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
|||||||
html_theme = "alabaster"
|
html_theme = "alabaster"
|
||||||
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
"extra_nav_links": {
|
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
|
||||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
#! /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,24 +59,17 @@ 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;
|
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||||
if (dataAddress != store_address_t::invalid()) {
|
if (result != returnvalue::OK) {
|
||||||
hasAdditionalData = true;
|
CommandMessage reply;
|
||||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||||
if (result != returnvalue::OK) {
|
queueToUse->sendMessage(commandedBy, &reply);
|
||||||
CommandMessage reply;
|
return;
|
||||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
|
||||||
queueToUse->sendMessage(commandedBy, &reply);
|
|
||||||
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,
|
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
uint32_t size);
|
||||||
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,9 +2,7 @@
|
|||||||
#define FSFW_CFDP_H
|
#define FSFW_CFDP_H
|
||||||
|
|
||||||
#include "cfdp/definitions.h"
|
#include "cfdp/definitions.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"
|
||||||
|
@ -21,7 +21,7 @@ struct FileSize : public SerializeIF {
|
|||||||
this->largeFile = isLarge;
|
this->largeFile = isLarge;
|
||||||
return serialize(buffer, size, maxSize, streamEndianness);
|
return serialize(buffer, size, maxSize, streamEndianness);
|
||||||
}
|
}
|
||||||
|
using SerializeIF::serialize;
|
||||||
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 {
|
||||||
if (not largeFile) {
|
if (not largeFile) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "fsfw/serialize/SerializeAdapter.h"
|
#include "fsfw/serialize/SerializeAdapter.h"
|
||||||
#include "fsfw/serviceinterface.h"
|
#include "fsfw/serviceinterface.h"
|
||||||
|
|
||||||
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, size_t value) : VarLenField() {
|
cfdp::VarLenField::VarLenField(cfdp::WidthInBytes width, uint64_t value) : VarLenField() {
|
||||||
ReturnValue_t result = this->setValue(width, value);
|
ReturnValue_t result = this->setValue(width, value);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
#if FSFW_DISABLE_PRINTOUT == 0
|
#if FSFW_DISABLE_PRINTOUT == 0
|
||||||
@ -20,7 +20,7 @@ cfdp::VarLenField::VarLenField() : width(cfdp::WidthInBytes::ONE_BYTE) { value.o
|
|||||||
|
|
||||||
cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
|
cfdp::WidthInBytes cfdp::VarLenField::getWidth() const { return width; }
|
||||||
|
|
||||||
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_t value_) {
|
ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, uint64_t value_) {
|
||||||
switch (widthInBytes) {
|
switch (widthInBytes) {
|
||||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||||
if (value_ > UINT8_MAX) {
|
if (value_ > UINT8_MAX) {
|
||||||
@ -51,7 +51,7 @@ ReturnValue_t cfdp::VarLenField::setValue(cfdp::WidthInBytes widthInBytes, size_
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t cfdp::VarLenField::getValue() const {
|
uint64_t cfdp::VarLenField::getValue() const {
|
||||||
switch (width) {
|
switch (width) {
|
||||||
case (cfdp::WidthInBytes::ONE_BYTE): {
|
case (cfdp::WidthInBytes::ONE_BYTE): {
|
||||||
return value.oneByte;
|
return value.oneByte;
|
||||||
|
@ -25,13 +25,13 @@ class VarLenField : public SerializeIF {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
explicit VarLenField(UnsignedByteField<T> byteField);
|
explicit VarLenField(UnsignedByteField<T> byteField);
|
||||||
|
|
||||||
VarLenField(cfdp::WidthInBytes width, size_t value);
|
VarLenField(cfdp::WidthInBytes width, uint64_t value);
|
||||||
|
|
||||||
bool operator==(const VarLenField &other) const;
|
bool operator==(const VarLenField &other) const;
|
||||||
bool operator!=(const VarLenField &other) const;
|
bool operator!=(const VarLenField &other) const;
|
||||||
bool operator<(const VarLenField &other) const;
|
bool operator<(const VarLenField &other) const;
|
||||||
|
|
||||||
ReturnValue_t setValue(cfdp::WidthInBytes, size_t value);
|
ReturnValue_t setValue(cfdp::WidthInBytes, uint64_t value);
|
||||||
|
|
||||||
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;
|
||||||
@ -42,7 +42,7 @@ class VarLenField : public SerializeIF {
|
|||||||
Endianness streamEndianness);
|
Endianness streamEndianness);
|
||||||
|
|
||||||
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
|
[[nodiscard]] cfdp::WidthInBytes getWidth() const;
|
||||||
[[nodiscard]] size_t getValue() const;
|
[[nodiscard]] uint64_t getValue() const;
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
|
friend std::ostream &operator<<(std::ostream &os, const VarLenField &id) {
|
||||||
@ -53,6 +53,7 @@ class VarLenField : public SerializeIF {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using SerializeIF::deSerialize;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
#include "fsfw/returnvalues/FwClassIds.h"
|
#include "fsfw/returnvalues/FwClassIds.h"
|
||||||
#include "fsfw/returnvalues/returnvalue.h"
|
#include "fsfw/returnvalues/returnvalue.h"
|
||||||
|
|
||||||
|
// Thanks, windows
|
||||||
|
#ifdef NO_ERROR
|
||||||
|
#undef NO_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace cfdp {
|
namespace cfdp {
|
||||||
|
|
||||||
static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
|
static constexpr char CFDP_VERSION_2_NAME[] = "CCSDS 727.0-B-5";
|
||||||
|
@ -1,2 +1 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||||
FaultHandlerBase.cpp UserBase.cpp)
|
|
||||||
|
@ -1,546 +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 (result != returnvalue::OK) {
|
|
||||||
// TODO: Proper Error handling
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2)
|
|
||||||
<< result << std::endl;
|
|
||||||
#endif
|
|
||||||
tp.vfsErrorCount++;
|
|
||||||
if (tp.vfsErrorCount < 3) {
|
|
||||||
// TODO: Provide execution step as parameter
|
|
||||||
fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast<uint8_t>(fsmRes.step),
|
|
||||||
result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
|
||||||
tp.vfsErrorCount = 0;
|
|
||||||
}
|
|
||||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
|
||||||
tp.progress = offset.value() + fileSegmentLen;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
size_t sourceNameSize = 0;
|
|
||||||
|
|
||||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
|
||||||
if (sourceNameSize + 1 > tp.sourceName.size()) {
|
|
||||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large");
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
|
||||||
tp.sourceName[sourceNameSize] = '\0';
|
|
||||||
size_t destNameSize = 0;
|
|
||||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
|
||||||
if (destNameSize + 1 > tp.destName.size()) {
|
|
||||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large");
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
|
||||||
tp.destName[destNameSize] = '\0';
|
|
||||||
|
|
||||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
|
||||||
// so there is no need to create a file or truncate an existing file
|
|
||||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
|
||||||
FilesystemParams fparams(tp.destName.data());
|
|
||||||
// handling to allow only specifying target directory. Example:
|
|
||||||
// Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt
|
|
||||||
if (dp.user.vfs.isDirectory(tp.destName.data())) {
|
|
||||||
result = tryBuildingAbsoluteDestName(destNameSize);
|
|
||||||
if (result != OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dp.user.vfs.fileExists(fparams)) {
|
|
||||||
result = dp.user.vfs.truncateFile(fparams);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error");
|
|
||||||
return FAILED;
|
|
||||||
// TODO: Relevant for filestore rejection error?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = dp.user.vfs.createFile(fparams);
|
|
||||||
if (result != OK) {
|
|
||||||
fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error");
|
|
||||||
return FAILED;
|
|
||||||
// TODO: Relevant for filestore rejection error?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EntityId sourceId;
|
|
||||||
reader.getSourceId(sourceId);
|
|
||||||
if (not dp.remoteCfgTable.getRemoteCfg(sourceId, &tp.remoteCfg)) {
|
|
||||||
// TODO: Warning, event etc.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler" << __func__
|
|
||||||
<< ": No remote configuration found for destination ID "
|
|
||||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
|
||||||
#endif
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
|
||||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
|
||||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
|
||||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
|
||||||
}
|
|
||||||
tp.checksumType = info.getChecksumType();
|
|
||||||
tp.closureRequested = info.isClosureRequested();
|
|
||||||
reader.fillConfig(tp.pduConf);
|
|
||||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
|
||||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
|
||||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
|
||||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
|
||||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
|
||||||
params.fileSize = tp.fileSize.getSize();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) {
|
|
||||||
char baseNameBuf[tp.destName.size()]{};
|
|
||||||
FilesystemParams fparamsSrc(tp.sourceName.data());
|
|
||||||
size_t baseNameLen = 0;
|
|
||||||
ReturnValue_t result =
|
|
||||||
dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen);
|
|
||||||
if (result != returnvalue::OK or baseNameLen == 0) {
|
|
||||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name");
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
// Destination name + slash + base name + null termination
|
|
||||||
if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) {
|
|
||||||
fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0,
|
|
||||||
"dest filename too large after adding source base name");
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
tp.destName[destNameSize++] = '/';
|
|
||||||
std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen);
|
|
||||||
destNameSize += baseNameLen;
|
|
||||||
tp.destName[destNameSize++] = '\0';
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) {
|
|
||||||
fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR,
|
|
||||||
static_cast<uint8_t>(fsmRes.step), result);
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "cfdp::DestHandler: " << info << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void cfdp::DestHandler::finish() {
|
|
||||||
tp.reset();
|
|
||||||
dp.packetListRef.clear();
|
|
||||||
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,206 +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 : uint8_t {
|
|
||||||
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;
|
|
||||||
vfsErrorCount = 0;
|
|
||||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
|
||||||
bool closureRequested = false;
|
|
||||||
uint16_t vfsErrorCount = 0;
|
|
||||||
std::vector<char> sourceName;
|
|
||||||
std::vector<char> destName;
|
|
||||||
cfdp::FileSize fileSize;
|
|
||||||
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 tryBuildingAbsoluteDestName(size_t destNameSize);
|
|
||||||
ReturnValue_t sendFinishedPdu();
|
|
||||||
ReturnValue_t noticeOfCompletion();
|
|
||||||
ReturnValue_t checksumVerification();
|
|
||||||
void fileErrorHandler(Event event, ReturnValue_t result, const char* info);
|
|
||||||
const FsmResult& updateFsmRes(uint8_t errors);
|
|
||||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
|
||||||
void finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // 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,18 +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);
|
|
||||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
|
||||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
|
||||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
|
|
||||||
} // namespace cfdp
|
|
||||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||||
|
@ -42,6 +42,6 @@ size_t EofInfo::getSerializedSize(bool fssLarge) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t EofInfo::setFileSize(size_t fileSize, bool isLarge) {
|
ReturnValue_t EofInfo::setFileSize(uint64_t fileSize, bool isLarge) {
|
||||||
return this->fileSize.setFileSize(fileSize, isLarge);
|
return this->fileSize.setFileSize(fileSize, isLarge);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ struct EofInfo {
|
|||||||
void setChecksum(uint32_t checksum);
|
void setChecksum(uint32_t checksum);
|
||||||
void setConditionCode(cfdp::ConditionCode conditionCode);
|
void setConditionCode(cfdp::ConditionCode conditionCode);
|
||||||
void setFaultLoc(EntityIdTlv* faultLoc);
|
void setFaultLoc(EntityIdTlv* faultLoc);
|
||||||
ReturnValue_t setFileSize(size_t size, bool isLarge);
|
ReturnValue_t setFileSize(uint64_t size, bool isLarge);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cfdp::ConditionCode conditionCode;
|
cfdp::ConditionCode conditionCode;
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
#include "FinishedPduReader.h"
|
#include "FinishedPduReader.h"
|
||||||
|
|
||||||
|
// Thanks, windows
|
||||||
|
#ifdef NO_ERROR
|
||||||
|
#undef NO_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
FinishPduReader::FinishPduReader(const uint8_t* pduBuf, size_t maxSize, FinishedInfo& info)
|
FinishPduReader::FinishPduReader(const uint8_t* pduBuf, size_t maxSize, FinishedInfo& info)
|
||||||
: FileDirectiveReader(pduBuf, maxSize), finishedInfo(info) {}
|
: FileDirectiveReader(pduBuf, maxSize), finishedInfo(info) {}
|
||||||
|
|
||||||
|
@ -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() - 1) << 4) |
|
**buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 |
|
||||||
segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1);
|
pduConf.seqNum.getWidth();
|
||||||
*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) & 0b111) + 1);
|
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte >> 4) & 0x07);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
|
cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const {
|
||||||
return static_cast<cfdp::WidthInBytes>((pointers.fixedHeader->fourthByte & 0b111) + 1);
|
return static_cast<cfdp::WidthInBytes>(pointers.fixedHeader->fourthByte & 0x07);
|
||||||
}
|
}
|
||||||
|
|
||||||
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const {
|
||||||
|
@ -23,6 +23,7 @@ class EntityIdTlv : public TlvIF {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
ReturnValue_t deSerialize(cfdp::Tlv& tlv, Endianness endianness);
|
||||||
|
|
||||||
|
using SerializeIF::deSerialize;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ class FilestoreRequestTlv : public cfdp::FilestoreTlvBase {
|
|||||||
*/
|
*/
|
||||||
ReturnValue_t deSerialize(cfdp::Tlv &tlv, Endianness endianness);
|
ReturnValue_t deSerialize(cfdp::Tlv &tlv, Endianness endianness);
|
||||||
|
|
||||||
|
using SerializeIF::deSerialize;
|
||||||
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,7 @@ 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;
|
||||||
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,7 +12,6 @@ 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];
|
||||||
|
@ -4,31 +4,48 @@
|
|||||||
#include "fsfw/ipc/QueueFactory.h"
|
#include "fsfw/ipc/QueueFactory.h"
|
||||||
#include "fsfw/objectmanager/ObjectManager.h"
|
#include "fsfw/objectmanager/ObjectManager.h"
|
||||||
#include "fsfw/subsystem/SubsystemBase.h"
|
#include "fsfw/subsystem/SubsystemBase.h"
|
||||||
#include "fsfw/subsystem/helper.h"
|
|
||||||
|
|
||||||
ControllerBase::ControllerBase(object_id_t setObjectId, size_t commandQueueDepth)
|
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||||
|
size_t commandQueueDepth)
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
|
parentId(parentId),
|
||||||
mode(MODE_OFF),
|
mode(MODE_OFF),
|
||||||
submode(SUBMODE_NONE),
|
submode(SUBMODE_NONE),
|
||||||
modeHelper(this),
|
modeHelper(this),
|
||||||
healthHelper(this, setObjectId) {
|
healthHelper(this, setObjectId) {
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
|
||||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::initialize() {
|
ReturnValue_t ControllerBase::initialize() {
|
||||||
ReturnValue_t result = modeHelper.initialize();
|
ReturnValue_t result = SystemObject::initialize();
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = healthHelper.initialize();
|
|
||||||
|
MessageQueueId_t parentQueue = 0;
|
||||||
|
if (parentId != objects::NO_OBJECT) {
|
||||||
|
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||||
|
if (parent == nullptr) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
parentQueue = parent->getCommandQueue();
|
||||||
|
|
||||||
|
parent->registerChild(getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
result = healthHelper.initialize(parentQueue);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return SystemObject::initialize();
|
|
||||||
|
result = modeHelper.initialize(parentQueue);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||||
@ -58,7 +75,7 @@ void ControllerBase::handleQueue() {
|
|||||||
|
|
||||||
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) {
|
||||||
changeHK(this->mode, this->submode, false);
|
changeHK(this->mode, this->submode, false);
|
||||||
triggerEvent(CHANGING_MODE, mode_, submode_);
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
mode = mode_;
|
mode = mode_;
|
||||||
submode = submode_;
|
submode = submode_;
|
||||||
modeHelper.modeChanged(mode, submode);
|
modeHelper.modeChanged(mode, submode);
|
||||||
@ -101,13 +118,3 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
|||||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
||||||
|
|
||||||
const HasHealthIF* ControllerBase::getOptHealthIF() const { return this; }
|
|
||||||
|
|
||||||
const HasModesIF& ControllerBase::getModeIF() const { return *this; }
|
|
||||||
|
|
||||||
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
|
|
||||||
|
|
||||||
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
|
||||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
|
||||||
}
|
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
#include "fsfw/modes/HasModesIF.h"
|
#include "fsfw/modes/HasModesIF.h"
|
||||||
#include "fsfw/modes/ModeHelper.h"
|
#include "fsfw/modes/ModeHelper.h"
|
||||||
#include "fsfw/objectmanager/SystemObject.h"
|
#include "fsfw/objectmanager/SystemObject.h"
|
||||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
|
||||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
|
||||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
|
||||||
@ -21,18 +18,13 @@
|
|||||||
class ControllerBase : public HasModesIF,
|
class ControllerBase : public HasModesIF,
|
||||||
public HasHealthIF,
|
public HasHealthIF,
|
||||||
public ExecutableObjectIF,
|
public ExecutableObjectIF,
|
||||||
public ModeTreeChildIF,
|
|
||||||
public ModeTreeConnectionIF,
|
|
||||||
public SystemObject {
|
public SystemObject {
|
||||||
public:
|
public:
|
||||||
static const Mode_t MODE_NORMAL = 2;
|
static const Mode_t MODE_NORMAL = 2;
|
||||||
|
|
||||||
ControllerBase(object_id_t setObjectId, size_t commandQueueDepth = 3);
|
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||||
~ControllerBase() override;
|
~ControllerBase() override;
|
||||||
|
|
||||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
|
||||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
|
||||||
|
|
||||||
/** SystemObject override */
|
/** SystemObject override */
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
@ -46,8 +38,6 @@ class ControllerBase : public HasModesIF,
|
|||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
void setTaskIF(PeriodicTaskIF *task) override;
|
void setTaskIF(PeriodicTaskIF *task) override;
|
||||||
ReturnValue_t initializeAfterTaskCreation() override;
|
ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
const HasHealthIF *getOptHealthIF() const override;
|
|
||||||
const HasModesIF &getModeIF() const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -66,6 +56,8 @@ class ControllerBase : public HasModesIF,
|
|||||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode) override = 0;
|
uint32_t *msToReachTheMode) override = 0;
|
||||||
|
|
||||||
|
const object_id_t parentId;
|
||||||
|
|
||||||
Mode_t mode;
|
Mode_t mode;
|
||||||
|
|
||||||
Submode_t submode;
|
Submode_t submode;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include "fsfw/controller/ExtendedControllerBase.h"
|
#include "fsfw/controller/ExtendedControllerBase.h"
|
||||||
|
|
||||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth)
|
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
||||||
: ControllerBase(objectId, commandQueueDepth),
|
size_t commandQueueDepth)
|
||||||
|
: ControllerBase(objectId, parentId, commandQueueDepth),
|
||||||
poolManager(this, commandQueue),
|
poolManager(this, commandQueue),
|
||||||
actionHelper(this, commandQueue) {}
|
actionHelper(this, commandQueue) {}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ class ExtendedControllerBase : public ControllerBase,
|
|||||||
public HasActionsIF,
|
public HasActionsIF,
|
||||||
public HasLocalDataPoolIF {
|
public HasLocalDataPoolIF {
|
||||||
public:
|
public:
|
||||||
ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth = 3);
|
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||||
~ExtendedControllerBase() override;
|
~ExtendedControllerBase() override;
|
||||||
|
|
||||||
/* SystemObjectIF overrides */
|
/* SystemObjectIF overrides */
|
||||||
|
@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time
|
|||||||
timeval timeSinceEpoch = time - epoch;
|
timeval timeSinceEpoch = time - epoch;
|
||||||
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.;
|
||||||
|
|
||||||
double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30;
|
double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365;
|
||||||
|
|
||||||
if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) {
|
if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) {
|
||||||
return TLE_TOO_OLD;
|
return TLE_TOO_OLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,8 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() {
|
ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) {
|
||||||
|
setNonDiagnosticIntervalFactor(nonDiagInvlFactor);
|
||||||
return initializeHousekeepingPoolEntriesOnce();
|
return initializeHousekeepingPoolEntriesOnce();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,9 +506,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
|||||||
float newCollIntvl = 0;
|
float newCollIntvl = 0;
|
||||||
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
|
HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl);
|
||||||
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
|
if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) {
|
||||||
result = changeCollectionInterval(sid, newCollIntvl);
|
result = changeCollectionInterval(sid, newCollIntvl, true);
|
||||||
} else {
|
} else {
|
||||||
result = changeCollectionInterval(sid, newCollIntvl);
|
result = changeCollectionInterval(sid, newCollIntvl, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -569,10 +570,6 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
|||||||
|
|
||||||
CommandMessage reply;
|
CommandMessage reply;
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
if (result == WRONG_HK_PACKET_TYPE) {
|
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
|
||||||
WRONG_HK_PACKET_TYPE);
|
|
||||||
}
|
|
||||||
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
||||||
} else {
|
} else {
|
||||||
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
||||||
@ -660,6 +657,10 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke
|
|||||||
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) {
|
||||||
|
this->nonDiagnosticIntervalFactor = nonDiagInvlFactor;
|
||||||
|
}
|
||||||
|
|
||||||
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) {
|
||||||
sid_t sid = receiver.dataId.sid;
|
sid_t sid = receiver.dataId.sid;
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
@ -713,15 +714,15 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena
|
|||||||
|
|
||||||
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
|
if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or
|
||||||
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
(not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) {
|
||||||
return returnvalue::OK;
|
return REPORTING_STATUS_UNCHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable);
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||||
float newCollectionInterval) {
|
bool isDiagnostics) {
|
||||||
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid);
|
||||||
if (dataSet == nullptr) {
|
if (dataSet == nullptr) {
|
||||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
|
printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval",
|
||||||
@ -729,6 +730,11 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid,
|
|||||||
return DATASET_NOT_FOUND;
|
return DATASET_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet);
|
||||||
|
if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) {
|
||||||
|
return WRONG_HK_PACKET_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
PeriodicHousekeepingHelper* periodicHelper =
|
PeriodicHousekeepingHelper* periodicHelper =
|
||||||
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet);
|
||||||
|
|
||||||
@ -819,8 +825,6 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
|||||||
errorPrint = "Dataset not found";
|
errorPrint = "Dataset not found";
|
||||||
} else if (error == POOLOBJECT_NOT_FOUND) {
|
} else if (error == POOLOBJECT_NOT_FOUND) {
|
||||||
errorPrint = "Pool Object not found";
|
errorPrint = "Pool Object not found";
|
||||||
} else if (error == WRONG_HK_PACKET_TYPE) {
|
|
||||||
errorPrint = "Wrong Packet Type";
|
|
||||||
} else if (error == returnvalue::FAILED) {
|
} else if (error == returnvalue::FAILED) {
|
||||||
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
||||||
errorPrint = "Generic Warning";
|
errorPrint = "Generic Warning";
|
||||||
|
@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
* @param nonDiagInvlFactor
|
* @param nonDiagInvlFactor
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t initializeAfterTaskCreation();
|
ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This should be called in the periodic handler of the owner.
|
* @brief This should be called in the periodic handler of the owner.
|
||||||
@ -152,6 +152,17 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
MessageQueueId_t targetQueueId,
|
MessageQueueId_t targetQueueId,
|
||||||
bool generateSnapshot) override;
|
bool generateSnapshot) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-Diagnostics packets usually have a lower minimum sampling frequency
|
||||||
|
* than diagnostic packets.
|
||||||
|
* A factor can be specified to determine the minimum sampling frequency
|
||||||
|
* for non-diagnostic packets. The minimum sampling frequency of the
|
||||||
|
* diagnostics packets,which is usually jusst the period of the
|
||||||
|
* performOperation calls, is multiplied with that factor.
|
||||||
|
* @param factor
|
||||||
|
*/
|
||||||
|
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The manager is also able to handle housekeeping messages.
|
* @brief The manager is also able to handle housekeeping messages.
|
||||||
* @details
|
* @details
|
||||||
@ -174,7 +185,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet,
|
ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet,
|
||||||
bool forDownlink,
|
bool forDownlink,
|
||||||
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
|
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
|
||||||
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval);
|
|
||||||
|
|
||||||
HasLocalDataPoolIF* getOwner();
|
HasLocalDataPoolIF* getOwner();
|
||||||
|
|
||||||
@ -338,6 +348,8 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
|
|
||||||
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
|
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
|
||||||
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
|
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
|
||||||
|
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
|
||||||
|
bool isDiagnostics);
|
||||||
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
|
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
|
||||||
|
|
||||||
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
|
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
|
||||||
@ -352,6 +364,10 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces
|
|||||||
void printWarningOrError(sif::OutputTypes outputType, const char* functionName,
|
void printWarningOrError(sif::OutputTypes outputType, const char* functionName,
|
||||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||||
const char* errorPrint = nullptr);
|
const char* errorPrint = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ProvidesDataPoolSubscriptionIF::subscribeForPeriodicPacket;
|
||||||
|
using ProvidesDataPoolSubscriptionIF::subscribeForUpdatePacket;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -250,8 +250,9 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) {
|
|||||||
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; }
|
||||||
|
|
||||||
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval,
|
||||||
dur_millis_t minimumPeriodicInterval) {
|
dur_millis_t minimumPeriodicInterval,
|
||||||
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval);
|
uint8_t nonDiagIntervalFactor) {
|
||||||
|
periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; }
|
||||||
|
@ -162,7 +162,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||||||
object_id_t getCreatorObjectId();
|
object_id_t getCreatorObjectId();
|
||||||
|
|
||||||
bool getReportingEnabled() const;
|
bool getReportingEnabled() const;
|
||||||
void setReportingEnabled(bool enabled);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current periodic HK generation interval this set
|
* Returns the current periodic HK generation interval this set
|
||||||
@ -190,8 +189,10 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
|||||||
* Used for periodic generation.
|
* Used for periodic generation.
|
||||||
*/
|
*/
|
||||||
bool reportingEnabled = false;
|
bool reportingEnabled = false;
|
||||||
|
void setReportingEnabled(bool enabled);
|
||||||
|
|
||||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||||
|
uint8_t nonDiagIntervalFactor = 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the valid state of a dataset is always relevant to the whole
|
* If the valid state of a dataset is always relevant to the whole
|
||||||
|
@ -12,8 +12,10 @@ class LocalPoolDataSetAttorney {
|
|||||||
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); }
|
||||||
|
|
||||||
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval,
|
||||||
uint32_t minimumPeriodicIntervalMs) {
|
uint32_t minimumPeriodicIntervalMs,
|
||||||
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs);
|
uint8_t nonDiagIntervalFactor = 5) {
|
||||||
|
set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs,
|
||||||
|
nonDiagIntervalFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||||
|
|
||||||
AssemblyBase::AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth)
|
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth)
|
||||||
: SubsystemBase(objectId, MODE_OFF, commandQueueDepth),
|
: SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||||
internalState(STATE_NONE),
|
internalState(STATE_NONE),
|
||||||
recoveryState(RECOVERY_IDLE),
|
recoveryState(RECOVERY_IDLE),
|
||||||
recoveringDevice(childrenMap.end()),
|
recoveringDevice(childrenMap.end()),
|
||||||
@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
|
|||||||
|
|
||||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
doStartTransition(mode, submode);
|
doStartTransition(mode, submode);
|
||||||
triggerModeHelperEvents(mode, submode);
|
if (modeHelper.isForced()) {
|
||||||
|
triggerEvent(FORCING_MODE, mode, submode);
|
||||||
|
} else {
|
||||||
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||||
@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
|||||||
}
|
}
|
||||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
triggerEvent(TRYING_RECOVERY);
|
||||||
recoveryState = RECOVERY_STARTED;
|
recoveryState = RECOVERY_STARTED;
|
||||||
recoveringDevice = iter;
|
recoveringDevice = iter;
|
||||||
// The user needs to take care of commanding the children off in commandChildren
|
|
||||||
doStartTransition(targetMode, targetSubmode);
|
doStartTransition(targetMode, targetSubmode);
|
||||||
} else {
|
} else {
|
||||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||||
@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
|||||||
bool AssemblyBase::checkAndHandleRecovery() {
|
bool AssemblyBase::checkAndHandleRecovery() {
|
||||||
switch (recoveryState) {
|
switch (recoveryState) {
|
||||||
case RECOVERY_STARTED:
|
case RECOVERY_STARTED:
|
||||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
|
||||||
// to wait for an off time period.
|
|
||||||
// TODO: make time period configurable
|
|
||||||
recoveryState = RECOVERY_WAIT;
|
recoveryState = RECOVERY_WAIT;
|
||||||
recoveryOffTimer.resetTimer();
|
recoveryOffTimer.resetTimer();
|
||||||
return true;
|
return true;
|
||||||
@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
|||||||
modeHelper.setForced(true);
|
modeHelper.setForced(true);
|
||||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
|
||||||
if (modeHelper.isForced()) {
|
|
||||||
triggerEvent(FORCING_MODE, mode, submode);
|
|
||||||
} else {
|
|
||||||
triggerEvent(CHANGING_MODE, mode, submode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -12,8 +12,7 @@
|
|||||||
* Documentation: Dissertation Baetz p.156, 157.
|
* Documentation: Dissertation Baetz p.156, 157.
|
||||||
*
|
*
|
||||||
* This class reduces the complexity of controller components which would
|
* This class reduces the complexity of controller components which would
|
||||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
* otherwise be needed for the handling of redundant devices.
|
||||||
* manage the mode keeping and recovery of non-redundant devices
|
|
||||||
*
|
*
|
||||||
* The template class monitors mode and health state of its children
|
* The template class monitors mode and health state of its children
|
||||||
* and checks availability of devices on every detected change.
|
* and checks availability of devices on every detected change.
|
||||||
@ -27,9 +26,11 @@
|
|||||||
*
|
*
|
||||||
* Important:
|
* Important:
|
||||||
*
|
*
|
||||||
* The implementation must call #registerChild for all commanded children during initialization.
|
* The implementation must call registerChild(object_id_t child)
|
||||||
|
* for all commanded children during initialization.
|
||||||
* The implementation must call the initialization function of the base class.
|
* The implementation must call the initialization function of the base class.
|
||||||
* (This will call the function in SubsystemBase)
|
* (This will call the function in SubsystemBase)
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
class AssemblyBase : public SubsystemBase {
|
class AssemblyBase : public SubsystemBase {
|
||||||
public:
|
public:
|
||||||
@ -41,15 +42,14 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
||||||
|
|
||||||
AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth = 8);
|
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||||
virtual ~AssemblyBase();
|
virtual ~AssemblyBase();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
* Command children to reach [mode,submode] combination
|
||||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
* Can be done by setting #commandsOutstanding correctly,
|
||||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
* or using executeTable()
|
||||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
|
||||||
* @param mode
|
* @param mode
|
||||||
* @param submode
|
* @param submode
|
||||||
* @return
|
* @return
|
||||||
@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
|
|
||||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||||
|
|
||||||
/**
|
virtual void performChildOperation();
|
||||||
* @brief Default periodic handler
|
|
||||||
* @details
|
|
||||||
* This is the default periodic handler which will be called by the SubsystemBase
|
|
||||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
|
||||||
* of children objects
|
|
||||||
*/
|
|
||||||
virtual void performChildOperation() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function handles changed mode or health states of children
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
bool handleChildrenChanged();
|
bool handleChildrenChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
|
|
||||||
bool handleChildrenChangedHealth();
|
bool handleChildrenChangedHealth();
|
||||||
|
|
||||||
/**
|
|
||||||
* Core transition handler. The default implementation will only do something if
|
|
||||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
|
||||||
* from the #doPerformTransition call were executed successfully.
|
|
||||||
*
|
|
||||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
|
||||||
* determine whether the target mode was reached.
|
|
||||||
*
|
|
||||||
* There is some special handling for certain (internal) modes:
|
|
||||||
* - A second step is necessary. #commandChildren will be performed again
|
|
||||||
* - The device health was overwritten. #commandChildren will be called
|
|
||||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
|
||||||
*/
|
|
||||||
virtual void handleChildrenTransition();
|
virtual void handleChildrenTransition();
|
||||||
|
|
||||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
|
||||||
* change
|
|
||||||
* @param mode
|
|
||||||
* @param submode
|
|
||||||
*/
|
|
||||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||||
|
|
||||||
/**
|
|
||||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
|
||||||
* variables and then calling the #commandChildren function.
|
|
||||||
* @param mode
|
|
||||||
* @param submode
|
|
||||||
*/
|
|
||||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||||
|
|
||||||
virtual bool isInTransition();
|
virtual bool isInTransition();
|
||||||
@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
* Manages recovery of a device
|
* Manages recovery of a device
|
||||||
* @return true if recovery is still ongoing, false else.
|
* @return true if recovery is still ongoing, false else.
|
||||||
*/
|
*/
|
||||||
virtual bool checkAndHandleRecovery();
|
bool checkAndHandleRecovery();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to overwrite health state of one of the children.
|
* Helper method to overwrite health state of one of the children.
|
||||||
@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
|
|||||||
* @param objectId Must be a registered child.
|
* @param objectId Must be a registered child.
|
||||||
*/
|
*/
|
||||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||||
|
|
||||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||||
|
@ -3,12 +3,17 @@
|
|||||||
#include "fsfw/subsystem/SubsystemBase.h"
|
#include "fsfw/subsystem/SubsystemBase.h"
|
||||||
|
|
||||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
||||||
CookieIF* cookie, HasModeTreeChildrenIF& parent,
|
CookieIF* cookie, object_id_t hkDestination,
|
||||||
FailureIsolationBase* customFdir, size_t cmdQueueSize)
|
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||||
|
object_id_t parent, FailureIsolationBase* customFdir,
|
||||||
|
size_t cmdQueueSize)
|
||||||
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
||||||
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
||||||
parent(parent),
|
parentId(parent),
|
||||||
childHandlerFdir(setObjectId) {}
|
childHandlerFdir(setObjectId) {
|
||||||
|
this->setHkDestination(hkDestination);
|
||||||
|
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
|
||||||
|
}
|
||||||
|
|
||||||
ChildHandlerBase::~ChildHandlerBase() {}
|
ChildHandlerBase::~ChildHandlerBase() {}
|
||||||
|
|
||||||
@ -18,5 +23,21 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeviceHandlerBase::connectModeTreeParent(parent);
|
MessageQueueId_t parentQueue = 0;
|
||||||
|
|
||||||
|
if (parentId != objects::NO_OBJECT) {
|
||||||
|
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||||
|
if (parent == NULL) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
parentQueue = parent->getCommandQueue();
|
||||||
|
|
||||||
|
parent->registerChild(getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
healthHelper.setParentQueue(parentQueue);
|
||||||
|
|
||||||
|
modeHelper.setParentQueue(parentQueue);
|
||||||
|
|
||||||
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||||
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||||
|
|
||||||
#include <fsfw/subsystem/HasModeTreeChildrenIF.h>
|
|
||||||
|
|
||||||
#include "ChildHandlerFDIR.h"
|
#include "ChildHandlerFDIR.h"
|
||||||
#include "DeviceHandlerBase.h"
|
#include "DeviceHandlerBase.h"
|
||||||
|
|
||||||
class ChildHandlerBase : public DeviceHandlerBase {
|
class ChildHandlerBase : public DeviceHandlerBase {
|
||||||
public:
|
public:
|
||||||
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
||||||
HasModeTreeChildrenIF& parent, FailureIsolationBase* customFdir = nullptr,
|
object_id_t hkDestination, uint32_t thermalStatePoolId,
|
||||||
size_t cmdQueueSize = 20);
|
uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT,
|
||||||
|
FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20);
|
||||||
|
|
||||||
virtual ~ChildHandlerBase();
|
virtual ~ChildHandlerBase();
|
||||||
|
|
||||||
virtual ReturnValue_t initialize();
|
virtual ReturnValue_t initialize();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HasModeTreeChildrenIF& parent;
|
const uint32_t parentId;
|
||||||
ChildHandlerFDIR childHandlerFdir;
|
ChildHandlerFDIR childHandlerFdir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ class DeviceCommunicationIF {
|
|||||||
// is this needed if there is no open/close call?
|
// is this needed if there is no open/close call?
|
||||||
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05);
|
||||||
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06);
|
||||||
static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07);
|
|
||||||
|
|
||||||
virtual ~DeviceCommunicationIF() {}
|
virtual ~DeviceCommunicationIF() {}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "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"
|
||||||
@ -13,7 +12,6 @@
|
|||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||||
#include "fsfw/subsystem/SubsystemBase.h"
|
#include "fsfw/subsystem/SubsystemBase.h"
|
||||||
#include "fsfw/subsystem/helper.h"
|
|
||||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||||
|
|
||||||
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||||
@ -24,6 +22,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||||||
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
|
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
|
||||||
size_t cmdQueueSize)
|
size_t cmdQueueSize)
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
|
mode(MODE_OFF),
|
||||||
|
submode(SUBMODE_NONE),
|
||||||
wiretappingMode(OFF),
|
wiretappingMode(OFF),
|
||||||
storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
||||||
deviceCommunicationId(deviceCommunication),
|
deviceCommunicationId(deviceCommunication),
|
||||||
@ -38,13 +38,10 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||||||
defaultFDIRUsed(fdirInstance == nullptr),
|
defaultFDIRUsed(fdirInstance == nullptr),
|
||||||
switchOffWasReported(false),
|
switchOffWasReported(false),
|
||||||
childTransitionDelay(5000),
|
childTransitionDelay(5000),
|
||||||
mode(MODE_OFF),
|
|
||||||
submode(SUBMODE_NONE),
|
|
||||||
transitionSourceMode(_MODE_POWER_DOWN),
|
transitionSourceMode(_MODE_POWER_DOWN),
|
||||||
transitionSourceSubMode(SUBMODE_NONE) {
|
transitionSourceSubMode(SUBMODE_NONE) {
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||||
insertInCommandMap(RAW_COMMAND_ID);
|
insertInCommandMap(RAW_COMMAND_ID);
|
||||||
cookieInfo.state = COOKIE_UNUSED;
|
cookieInfo.state = COOKIE_UNUSED;
|
||||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||||
@ -52,13 +49,21 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
|||||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
||||||
"Invalid cookie");
|
"Invalid cookie");
|
||||||
}
|
}
|
||||||
|
if (this->fdirInstance == nullptr) {
|
||||||
|
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||||
this->hkDestination = hkDestination;
|
this->hkDestination = hkDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; }
|
void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId,
|
||||||
|
lp_id_t heaterRequestPoolId,
|
||||||
|
uint32_t thermalSetId) {
|
||||||
|
thermalSet =
|
||||||
|
new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId);
|
||||||
|
}
|
||||||
|
|
||||||
DeviceHandlerBase::~DeviceHandlerBase() {
|
DeviceHandlerBase::~DeviceHandlerBase() {
|
||||||
if (comCookie != nullptr) {
|
if (comCookie != nullptr) {
|
||||||
@ -124,10 +129,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (this->fdirInstance == nullptr) {
|
|
||||||
this->fdirInstance =
|
|
||||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
communicationInterface =
|
communicationInterface =
|
||||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||||
@ -222,11 +223,12 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
|||||||
fillCommandAndReplyMap();
|
fillCommandAndReplyMap();
|
||||||
|
|
||||||
if (thermalSet != nullptr) {
|
if (thermalSet != nullptr) {
|
||||||
PoolReadGuard pg(thermalSet);
|
|
||||||
// Set temperature target state to NON_OP.
|
// Set temperature target state to NON_OP.
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
result = thermalSet->read();
|
||||||
|
if (result == returnvalue::OK) {
|
||||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||||
thermalSet->heaterRequest.setValid(true);
|
thermalSet->heaterRequest.setValid(true);
|
||||||
|
thermalSet->commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,8 +321,7 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
if (mode != currentMode) {
|
if (mode != currentMode) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uint32_t currentUptime;
|
uint32_t currentUptime = Clock::getUptime_ms();
|
||||||
Clock::getUptime(¤tUptime);
|
|
||||||
if (currentUptime - timeoutStart >= childTransitionDelay) {
|
if (currentUptime - timeoutStart >= childTransitionDelay) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0
|
#if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0
|
||||||
char printout[60];
|
char printout[60];
|
||||||
@ -344,12 +345,12 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
setMode(_MODE_WAIT_ON);
|
setMode(_MODE_WAIT_ON);
|
||||||
break;
|
break;
|
||||||
case _MODE_WAIT_ON: {
|
case _MODE_WAIT_ON: {
|
||||||
uint32_t currentUptime;
|
uint32_t currentUptime = Clock::getUptime_ms();
|
||||||
Clock::getUptime(¤tUptime);
|
|
||||||
if (powerSwitcher != nullptr and
|
if (powerSwitcher != nullptr and
|
||||||
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||||
setMode(_MODE_POWER_DOWN);
|
setMode(_MODE_POWER_DOWN);
|
||||||
|
callChildStatemachine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ReturnValue_t switchState = getStateOfSwitches();
|
ReturnValue_t switchState = getStateOfSwitches();
|
||||||
@ -363,12 +364,12 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case _MODE_WAIT_OFF: {
|
case _MODE_WAIT_OFF: {
|
||||||
|
uint32_t currentUptime = Clock::getUptime_ms();
|
||||||
|
|
||||||
if (powerSwitcher == nullptr) {
|
if (powerSwitcher == nullptr) {
|
||||||
setMode(MODE_OFF);
|
setMode(MODE_OFF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uint32_t currentUptime;
|
|
||||||
Clock::getUptime(¤tUptime);
|
|
||||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||||
setMode(MODE_ERROR_ON);
|
setMode(MODE_ERROR_ON);
|
||||||
@ -376,7 +377,7 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
}
|
}
|
||||||
ReturnValue_t switchState = getStateOfSwitches();
|
ReturnValue_t switchState = getStateOfSwitches();
|
||||||
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
|
if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) {
|
||||||
setMode(MODE_OFF, SUBMODE_NONE);
|
setMode(_MODE_SWITCH_IS_OFF);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case MODE_OFF:
|
case MODE_OFF:
|
||||||
@ -389,6 +390,9 @@ void DeviceHandlerBase::doStateMachine() {
|
|||||||
case MODE_NORMAL:
|
case MODE_NORMAL:
|
||||||
case MODE_ERROR_ON:
|
case MODE_ERROR_ON:
|
||||||
break;
|
break;
|
||||||
|
case _MODE_SWITCH_IS_OFF:
|
||||||
|
setMode(MODE_OFF, SUBMODE_NONE);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
|
triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode);
|
||||||
setMode(_MODE_POWER_DOWN, 0);
|
setMode(_MODE_POWER_DOWN, 0);
|
||||||
@ -560,40 +564,25 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||||
/**
|
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||||
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
|
// changeHK(mode, submode, false);
|
||||||
*/
|
|
||||||
if (newMode == MODE_ON and continueToNormal) {
|
|
||||||
continueToNormal = false;
|
|
||||||
// TODO: Check whether the following two lines are okay to do so.
|
|
||||||
transitionSourceMode = MODE_ON;
|
|
||||||
transitionSourceSubMode = newSubmode;
|
|
||||||
mode = _MODE_TO_NORMAL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
submode = newSubmode;
|
submode = newSubmode;
|
||||||
mode = newMode;
|
mode = newMode;
|
||||||
modeChanged();
|
modeChanged();
|
||||||
setNormalDatapoolEntriesInvalid();
|
setNormalDatapoolEntriesInvalid();
|
||||||
if (newMode == MODE_OFF) {
|
|
||||||
disableCommandsAndReplies();
|
|
||||||
}
|
|
||||||
if (!isTransitionalMode()) {
|
if (!isTransitionalMode()) {
|
||||||
// clear this flag when a non-transitional Mode is reached to be safe
|
|
||||||
continueToNormal = false;
|
|
||||||
modeHelper.modeChanged(newMode, newSubmode);
|
modeHelper.modeChanged(newMode, newSubmode);
|
||||||
announceMode(false);
|
announceMode(false);
|
||||||
}
|
}
|
||||||
Clock::getUptime(&timeoutStart);
|
timeoutStart = Clock::getUptime_ms();
|
||||||
|
|
||||||
if (mode == MODE_OFF and thermalSet != nullptr) {
|
if (mode == MODE_OFF and thermalSet != nullptr) {
|
||||||
PoolReadGuard pg(thermalSet);
|
ReturnValue_t result = thermalSet->read();
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
if (result == returnvalue::OK) {
|
||||||
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||||
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
|
||||||
}
|
}
|
||||||
thermalSet->heaterRequest.setValid(true);
|
thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||||
@ -1066,7 +1055,8 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
|
|||||||
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
|
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SHOULDDO: throw away DHB and write a new one:
|
// SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the
|
||||||
|
// way, throw away DHB and write a new one:
|
||||||
// - Include power and thermal completely, but more modular :-)
|
// - Include power and thermal completely, but more modular :-)
|
||||||
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
|
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
|
||||||
// - Modularization?
|
// - Modularization?
|
||||||
@ -1078,12 +1068,13 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
|||||||
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
|
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
|
||||||
return TRANS_NOT_ALLOWED;
|
return TRANS_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
|
||||||
|
return TRANS_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
// Do not check thermal state for MODE_RAW
|
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
|
||||||
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
|
ReturnValue_t result = thermalSet->read();
|
||||||
(thermalSet != nullptr)) {
|
if (result == returnvalue::OK) {
|
||||||
PoolReadGuard pg(thermalSet);
|
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
|
||||||
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||||
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
(not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) {
|
||||||
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value);
|
||||||
@ -1096,7 +1087,6 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
|
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
|
||||||
continueToNormal = false;
|
|
||||||
switch (commandedMode) {
|
switch (commandedMode) {
|
||||||
case MODE_ON:
|
case MODE_ON:
|
||||||
handleTransitionToOnMode(commandedMode, commandedSubmode);
|
handleTransitionToOnMode(commandedMode, commandedSubmode);
|
||||||
@ -1126,9 +1116,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
|
|||||||
case MODE_NORMAL:
|
case MODE_NORMAL:
|
||||||
if (mode != MODE_OFF) {
|
if (mode != MODE_OFF) {
|
||||||
setTransition(MODE_NORMAL, commandedSubmode);
|
setTransition(MODE_NORMAL, commandedSubmode);
|
||||||
} else { // mode is off
|
} else {
|
||||||
continueToNormal = true;
|
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
|
||||||
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1144,10 +1133,11 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t
|
|||||||
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
|
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON);
|
||||||
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
|
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
|
||||||
if (thermalSet != nullptr) {
|
if (thermalSet != nullptr) {
|
||||||
PoolReadGuard pg(thermalSet);
|
ReturnValue_t result = thermalSet->read();
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
if (result == returnvalue::OK) {
|
||||||
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
|
||||||
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
|
||||||
|
thermalSet->commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1285,7 +1275,6 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
|||||||
if (iter->second.command != deviceCommandMap.end()) {
|
if (iter->second.command != deviceCommandMap.end()) {
|
||||||
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
||||||
|
|
||||||
// This may fail, but we'll ignore the fault.
|
|
||||||
if (queueId != NO_COMMANDER) {
|
if (queueId != NO_COMMANDER) {
|
||||||
// This may fail, but we'll ignore the fault.
|
// This may fail, but we'll ignore the fault.
|
||||||
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
||||||
@ -1464,17 +1453,15 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
|||||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||||
uint32_t parameter) {}
|
uint32_t parameter) {}
|
||||||
|
|
||||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
|
||||||
|
|
||||||
void DeviceHandlerBase::performOperationHook() {}
|
void DeviceHandlerBase::performOperationHook() {}
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||||
LocalDataPoolManager& poolManager) {
|
LocalDataPoolManager& poolManager) {
|
||||||
if (thermalStateCfg.has_value()) {
|
if (thermalSet != nullptr) {
|
||||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId,
|
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
|
||||||
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>());
|
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
|
||||||
localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId,
|
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
|
||||||
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>());
|
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>);
|
||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
@ -1487,12 +1474,8 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
|||||||
}
|
}
|
||||||
this->poolManager.initializeAfterTaskCreation();
|
this->poolManager.initializeAfterTaskCreation();
|
||||||
|
|
||||||
if (thermalStateCfg.has_value()) {
|
|
||||||
ThermalStateCfg& cfg = thermalStateCfg.value();
|
|
||||||
thermalSet = new DeviceHandlerThermalSet(this, cfg);
|
|
||||||
}
|
|
||||||
if (setStartupImmediately) {
|
if (setStartupImmediately) {
|
||||||
startTransition(MODE_ON, getInitialSubmode());
|
startTransition(MODE_ON, SUBMODE_NONE);
|
||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
@ -1522,10 +1505,7 @@ 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);
|
reply.second.dataSet->setValidity(false, true);
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
|
||||||
reply.second.dataSet->setValidity(false, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1579,52 +1559,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
|||||||
}
|
}
|
||||||
return commandIter->second.sendReplyTo;
|
return commandIter->second.sendReplyTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
|
||||||
|
|
||||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
|
||||||
this->powerSwitcher = switcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mode_t DeviceHandlerBase::getMode() { return mode; }
|
|
||||||
|
|
||||||
Submode_t DeviceHandlerBase::getSubmode() { return submode; }
|
|
||||||
|
|
||||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
|
||||||
for (auto& command : deviceCommandMap) {
|
|
||||||
if (command.second.isExecuting) {
|
|
||||||
command.second.isExecuting = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto& reply : deviceReplyMap) {
|
|
||||||
if (!reply.second.periodic) {
|
|
||||||
if (reply.second.countdown != nullptr) {
|
|
||||||
reply.second.countdown->timeOut();
|
|
||||||
} else {
|
|
||||||
reply.second.delayCycles = 0;
|
|
||||||
}
|
|
||||||
reply.second.active = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
|
||||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }
|
|
||||||
|
|
||||||
const HasModesIF& DeviceHandlerBase::getModeIF() const { return *this; }
|
|
||||||
|
|
||||||
ModeTreeChildIF& DeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
|
||||||
|
|
||||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
|
||||||
ReturnValue_t result) {
|
|
||||||
auto commandIter = deviceCommandMap.find(action);
|
|
||||||
if (commandIter == deviceCommandMap.end()) {
|
|
||||||
return MessageQueueIF::NO_QUEUE;
|
|
||||||
}
|
|
||||||
commandIter->second.isExecuting = false;
|
|
||||||
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
#define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "DeviceCommunicationIF.h"
|
#include "DeviceCommunicationIF.h"
|
||||||
#include "DeviceHandlerFailureIsolation.h"
|
#include "DeviceHandlerFailureIsolation.h"
|
||||||
@ -22,7 +21,6 @@
|
|||||||
#include "fsfw/returnvalues/returnvalue.h"
|
#include "fsfw/returnvalues/returnvalue.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
|
||||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||||
|
|
||||||
@ -85,8 +83,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
public HasModesIF,
|
public HasModesIF,
|
||||||
public HasHealthIF,
|
public HasHealthIF,
|
||||||
public HasActionsIF,
|
public HasActionsIF,
|
||||||
public ModeTreeChildIF,
|
|
||||||
public ModeTreeConnectionIF,
|
|
||||||
public ReceivesParameterMessagesIF,
|
public ReceivesParameterMessagesIF,
|
||||||
public HasLocalDataPoolIF {
|
public HasLocalDataPoolIF {
|
||||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||||
@ -106,51 +102,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||||
|
|
||||||
void setCustomFdir(FailureIsolationBase *fdir);
|
|
||||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* extending the modes of DeviceHandler IF for internal state machine
|
|
||||||
*/
|
|
||||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
|
||||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
|
||||||
//! This is a transitional state which can not be commanded. The device
|
|
||||||
//! handler performs all commands to get the device in a state ready to
|
|
||||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
|
||||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
|
||||||
//! This is a transitional state which can not be commanded.
|
|
||||||
//! The device handler performs all actions and commands to get the device
|
|
||||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
|
||||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
|
||||||
//! transition if available.
|
|
||||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
|
||||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
|
||||||
//! transition if available.
|
|
||||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
|
||||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
|
||||||
//! transition if available.
|
|
||||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
|
||||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
|
||||||
//! transition if available.
|
|
||||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
|
||||||
//! This is a transitional state which can not be commanded.
|
|
||||||
//! The device is shut down and ready to be switched off.
|
|
||||||
//! After the command to set the switch off has been sent,
|
|
||||||
//! the mode changes to @c _MODE_WAIT_OFF
|
|
||||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
|
||||||
//! This is a transitional state which can not be commanded. The device
|
|
||||||
//! will be switched on in this state. After the command to set the switch
|
|
||||||
//! on has been sent, the mode changes to @c _MODE_WAIT_ON.
|
|
||||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
|
||||||
//! This is a transitional state which can not be commanded. The switch has
|
|
||||||
//! been commanded off and the handler waits for it to be off.
|
|
||||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
|
||||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
|
||||||
//! This is a transitional state which can not be commanded. The switch
|
|
||||||
//! has been commanded on and the handler waits for it to be on.
|
|
||||||
//! When the switch is on, the mode changes to @c _MODE_TO_ON.
|
|
||||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
|
||||||
|
|
||||||
void setHkDestination(object_id_t hkDestination);
|
void setHkDestination(object_id_t hkDestination);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,12 +110,13 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* The device handler will then take care of creating local pool entries
|
* The device handler will then take care of creating local pool entries
|
||||||
* for the device thermal state and device heating request.
|
* for the device thermal state and device heating request.
|
||||||
* Custom local pool IDs can be assigned as well.
|
* Custom local pool IDs can be assigned as well.
|
||||||
|
* @param thermalStatePoolId
|
||||||
|
* @param thermalRequestPoolId
|
||||||
*/
|
*/
|
||||||
void enableThermalModule(ThermalStateCfg cfg);
|
void setThermalStateRequestPoolIds(
|
||||||
|
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
|
||||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to ease device handler development.
|
* @brief Helper function to ease device handler development.
|
||||||
* This will instruct the transition to MODE_ON immediately
|
* This will instruct the transition to MODE_ON immediately
|
||||||
@ -210,7 +162,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @param counter Specifies which Action to perform
|
* @param counter Specifies which Action to perform
|
||||||
* @return returnvalue::OK for successful execution
|
* @return returnvalue::OK for successful execution
|
||||||
*/
|
*/
|
||||||
ReturnValue_t performOperation(uint8_t counter) override;
|
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the device handler
|
* @brief Initializes the device handler
|
||||||
@ -220,14 +172,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* Calls fillCommandAndReplyMap().
|
* Calls fillCommandAndReplyMap().
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t initialize() override;
|
virtual ReturnValue_t initialize() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Intialization steps performed after all tasks have been created.
|
* @brief Intialization steps performed after all tasks have been created.
|
||||||
* This function will be called by the executing task.
|
* This function will be called by the executing task.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ReturnValue_t initializeAfterTaskCreation() override;
|
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||||
|
|
||||||
/** Destructor. */
|
/** Destructor. */
|
||||||
virtual ~DeviceHandlerBase();
|
virtual ~DeviceHandlerBase();
|
||||||
@ -244,8 +196,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
virtual object_id_t getObjectId() const override;
|
virtual object_id_t getObjectId() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a helper method for classes which are parent nodes in the mode tree.
|
|
||||||
* It registers the passed queue as the destination for mode and health messages.
|
|
||||||
* @param parentQueueId
|
* @param parentQueueId
|
||||||
*/
|
*/
|
||||||
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
||||||
@ -256,9 +206,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
|
|
||||||
Mode_t getTransitionSourceMode() const;
|
Mode_t getTransitionSourceMode() const;
|
||||||
Submode_t getTransitionSourceSubMode() const;
|
Submode_t getTransitionSourceSubMode() const;
|
||||||
virtual void getMode(Mode_t *mode, Submode_t *submode);
|
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||||
virtual HealthState getHealth() override;
|
HealthState getHealth() override;
|
||||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
ReturnValue_t setHealth(HealthState health) override;
|
||||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
|
||||||
ParameterWrapper *parameterWrapper,
|
ParameterWrapper *parameterWrapper,
|
||||||
const ParameterWrapper *newValues,
|
const ParameterWrapper *newValues,
|
||||||
@ -445,8 +395,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
||||||
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
||||||
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to get pending command. This is useful for devices
|
* Helper function to get pending command. This is useful for devices
|
||||||
* like SPI sensors to identify the last sent command.
|
* like SPI sensors to identify the last sent command.
|
||||||
@ -515,14 +463,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* @brief This is a helper method to insert replies in the reply map.
|
* @brief This is a helper method to insert replies in the reply map.
|
||||||
* @param deviceCommand Identifier of the reply to add.
|
* @param deviceCommand Identifier of the reply to add.
|
||||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||||
* until it times out.
|
* until it times out.
|
||||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||||
* Please note that periodic replies are disabled by default. You can enable them with
|
* Please note that periodic replies are disabled by default. You can enable them with
|
||||||
* #updatePeriodicReply
|
* #updatePeriodicReply
|
||||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||||
* to provide a pointer to a Countdown object which will signal the timeout
|
* to provide a pointer to a Countdown object which will signal the timeout
|
||||||
* when expired
|
* when expired
|
||||||
* @return - @c returnvalue::OK when the command was successfully inserted,
|
* @return - @c returnvalue::OK when the command was successfully inserted,
|
||||||
* - @c returnvalue::FAILED else.
|
* - @c returnvalue::FAILED else.
|
||||||
*/
|
*/
|
||||||
@ -707,12 +655,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||||
uint32_t parameter = 0);
|
uint32_t parameter = 0);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
|
||||||
* to startup immediately.
|
|
||||||
*/
|
|
||||||
virtual Submode_t getInitialSubmode();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||||
|
|
||||||
@ -742,18 +684,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
size_t rawPacketLen = 0;
|
size_t rawPacketLen = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current mode
|
* The mode the device handler is currently in.
|
||||||
*
|
* This should never be changed directly but only with setMode()
|
||||||
* set via setMode()
|
|
||||||
*/
|
*/
|
||||||
Mode_t getMode();
|
Mode_t mode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current Submode
|
* The submode the device handler is currently in.
|
||||||
*
|
* This should never be changed directly but only with setMode()
|
||||||
* set via setMode()
|
|
||||||
*/
|
*/
|
||||||
Submode_t getSubmode();
|
Submode_t submode;
|
||||||
|
|
||||||
/** This is the counter value from performOperation(). */
|
/** This is the counter value from performOperation(). */
|
||||||
uint8_t pstStep = 0;
|
uint8_t pstStep = 0;
|
||||||
@ -834,18 +773,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* This is used to keep track of pending replies.
|
* This is used to keep track of pending replies.
|
||||||
*/
|
*/
|
||||||
struct DeviceReplyInfo {
|
struct DeviceReplyInfo {
|
||||||
//! For Command-Reply combinations:
|
|
||||||
//! The maximum number of cycles the handler should wait for a reply
|
//! The maximum number of cycles the handler should wait for a reply
|
||||||
//! to this command.
|
//! to this command.
|
||||||
//!
|
|
||||||
//! Reply Only:
|
|
||||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
|
||||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
|
||||||
//! definition for delay
|
|
||||||
uint16_t maxDelayCycles;
|
uint16_t maxDelayCycles;
|
||||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
//! The currently remaining cycles the handler should wait for a reply,
|
||||||
//! For non-periodic replies without a command, this variable is unused.
|
//! 0 means there is no reply expected
|
||||||
//! A runtime value of 0 means there is no reply is currently expected.
|
|
||||||
uint16_t delayCycles;
|
uint16_t delayCycles;
|
||||||
size_t replyLen = 0; //!< Expected size of the reply.
|
size_t replyLen = 0; //!< Expected size of the reply.
|
||||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||||
@ -901,7 +833,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
/** Pointer to the used FDIR instance. If not provided by child,
|
/** Pointer to the used FDIR instance. If not provided by child,
|
||||||
* default class is instantiated. */
|
* default class is instantiated. */
|
||||||
FailureIsolationBase *fdirInstance;
|
FailureIsolationBase *fdirInstance;
|
||||||
object_id_t parent = objects::NO_OBJECT;
|
|
||||||
|
|
||||||
//! To correctly delete the default instance.
|
//! To correctly delete the default instance.
|
||||||
bool defaultFDIRUsed;
|
bool defaultFDIRUsed;
|
||||||
@ -922,8 +853,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
//! Object which may be the root cause of an identified fault.
|
//! Object which may be the root cause of an identified fault.
|
||||||
static object_id_t defaultFdirParentId;
|
static object_id_t defaultFdirParentId;
|
||||||
|
|
||||||
std::optional<ThermalStateCfg> thermalStateCfg;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a reply to a received device handler command.
|
* @brief Send a reply to a received device handler command.
|
||||||
*
|
*
|
||||||
@ -944,8 +873,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
|
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
|
||||||
*
|
*
|
||||||
* If the transition is complete, the mode should be set to the target mode,
|
* If the transition is complete, the mode should be set to the target mode,
|
||||||
* which can be deduced from the current mode (which is
|
* which can be deduced from the current mode which is
|
||||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
|
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
|
||||||
*
|
*
|
||||||
* The intended target submode is already set.
|
* The intended target submode is already set.
|
||||||
* The origin submode can be read in subModeFrom.
|
* The origin submode can be read in subModeFrom.
|
||||||
@ -1012,9 +941,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
LocalDataPoolManager *getHkManagerHandle() override;
|
LocalDataPoolManager *getHkManagerHandle() override;
|
||||||
|
|
||||||
const HasHealthIF *getOptHealthIF() const override;
|
|
||||||
const HasModesIF &getModeIF() const override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the delay cycle count of a reply.
|
* Returns the delay cycle count of a reply.
|
||||||
* A count != 0 indicates that the command is already executed.
|
* A count != 0 indicates that the command is already executed.
|
||||||
@ -1147,7 +1073,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
bool forceDirectTm = false);
|
bool forceDirectTm = false);
|
||||||
|
|
||||||
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
uint32_t *msToReachTheMode);
|
uint32_t *msToReachTheMode) override;
|
||||||
|
|
||||||
virtual ReturnValue_t letChildHandleMessage(CommandMessage *message);
|
virtual ReturnValue_t letChildHandleMessage(CommandMessage *message);
|
||||||
|
|
||||||
@ -1194,22 +1120,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
virtual ReturnValue_t doSendReadHook();
|
virtual ReturnValue_t doSendReadHook();
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a RMAP getRead command.
|
|
||||||
*
|
|
||||||
* The size of the getRead command is #maxDeviceReplyLen.
|
|
||||||
* This is always executed, independently from the current mode.
|
|
||||||
*/
|
|
||||||
virtual void doSendRead(void);
|
|
||||||
/**
|
|
||||||
* Check the getRead reply and the contained data.
|
|
||||||
*
|
|
||||||
* If data was received scanForReply() and, if successful, handleReply()
|
|
||||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
|
||||||
* is sent to the commanding object via commandQueue.
|
|
||||||
*/
|
|
||||||
virtual void doGetRead();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* State a cookie is in.
|
* State a cookie is in.
|
||||||
@ -1260,18 +1170,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
uint32_t childTransitionDelay;
|
uint32_t childTransitionDelay;
|
||||||
|
|
||||||
/**
|
|
||||||
* The mode the device handler is currently in.
|
|
||||||
* This should not be changed directly but only with setMode()
|
|
||||||
*/
|
|
||||||
Mode_t mode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The submode the device handler is currently in.
|
|
||||||
* This should not be changed directly but only with setMode()
|
|
||||||
*/
|
|
||||||
Submode_t submode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The mode the current transition originated from
|
* @brief The mode the current transition originated from
|
||||||
*
|
*
|
||||||
@ -1289,15 +1187,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
*/
|
*/
|
||||||
Submode_t transitionSourceSubMode;
|
Submode_t transitionSourceSubMode;
|
||||||
|
|
||||||
/**
|
|
||||||
* used to make the state machine continue from ON to NOMAL when
|
|
||||||
* a Device is commanded to NORMAL in OFF mode
|
|
||||||
*
|
|
||||||
* set in startTransition()
|
|
||||||
* evaluated in setMode() to continue to NORMAL when ON is reached
|
|
||||||
*/
|
|
||||||
bool continueToNormal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read the command queue
|
* read the command queue
|
||||||
*/
|
*/
|
||||||
@ -1366,6 +1255,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
* - if the action was successful, the reply timout counter is initialized
|
* - if the action was successful, the reply timout counter is initialized
|
||||||
*/
|
*/
|
||||||
void doGetWrite(void);
|
void doGetWrite(void);
|
||||||
|
/**
|
||||||
|
* Send a RMAP getRead command.
|
||||||
|
*
|
||||||
|
* The size of the getRead command is #maxDeviceReplyLen.
|
||||||
|
* This is always executed, independently from the current mode.
|
||||||
|
*/
|
||||||
|
void doSendRead(void);
|
||||||
|
/**
|
||||||
|
* Check the getRead reply and the contained data.
|
||||||
|
*
|
||||||
|
* If data was received scanForReply() and, if successful, handleReply()
|
||||||
|
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||||
|
* is sent to the commanding object via commandQueue.
|
||||||
|
*/
|
||||||
|
void doGetRead(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Resets replies which use a timeout to detect missed replies.
|
* @brief Resets replies which use a timeout to detect missed replies.
|
||||||
@ -1419,11 +1323,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
|||||||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||||
const char *errorPrint = nullptr);
|
const char *errorPrint = nullptr);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Disables all commands and replies when device is set to MODE_OFF
|
|
||||||
*/
|
|
||||||
void disableCommandsAndReplies();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||||
|
@ -10,9 +10,8 @@
|
|||||||
|
|
||||||
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
|
||||||
|
|
||||||
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent)
|
||||||
uint8_t eventQueueDepth)
|
: FailureIsolationBase(owner, parent),
|
||||||
: FailureIsolationBase(owner, parent, eventQueueDepth),
|
|
||||||
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS,
|
strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS,
|
||||||
parameterDomainBase++),
|
parameterDomainBase++),
|
||||||
missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS,
|
missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS,
|
||||||
@ -30,7 +29,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
|||||||
switch (event->getEvent()) {
|
switch (event->getEvent()) {
|
||||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
|
||||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||||
// Might cause some AssemblyBase cycles, so keep number low.
|
// Might cause some AssemblyBase cycles, so keep number low.
|
||||||
handleRecovery(event->getEvent());
|
handleRecovery(event->getEvent());
|
||||||
|
@ -13,8 +13,7 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase {
|
|||||||
friend class Heater;
|
friend class Heater;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent,
|
DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent);
|
||||||
uint8_t eventQueueDepth = 10);
|
|
||||||
~DeviceHandlerFailureIsolation();
|
~DeviceHandlerFailureIsolation();
|
||||||
ReturnValue_t initialize();
|
ReturnValue_t initialize();
|
||||||
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0);
|
||||||
|
@ -24,6 +24,9 @@ class DeviceHandlerIF {
|
|||||||
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
|
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
|
||||||
static const DeviceCommandId_t NO_COMMAND_ID = -2;
|
static const DeviceCommandId_t NO_COMMAND_ID = -2;
|
||||||
|
|
||||||
|
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||||
|
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||||
|
|
||||||
using dh_heater_request_t = uint8_t;
|
using dh_heater_request_t = uint8_t;
|
||||||
using dh_thermal_state_t = int8_t;
|
using dh_thermal_state_t = int8_t;
|
||||||
|
|
||||||
@ -51,6 +54,47 @@ class DeviceHandlerIF {
|
|||||||
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
|
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
|
||||||
//! can be commanded, which tries to switch off the device again.
|
//! can be commanded, which tries to switch off the device again.
|
||||||
static const Mode_t MODE_ERROR_ON = 4;
|
static const Mode_t MODE_ERROR_ON = 4;
|
||||||
|
//! This is a transitional state which can not be commanded. The device
|
||||||
|
//! handler performs all commands to get the device in a state ready to
|
||||||
|
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||||
|
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||||
|
//! This is a transitional state which can not be commanded.
|
||||||
|
//! The device handler performs all actions and commands to get the device
|
||||||
|
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||||
|
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||||
|
//! transition if available.
|
||||||
|
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||||
|
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||||
|
//! transition if available.
|
||||||
|
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||||
|
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||||
|
//! transition if available.
|
||||||
|
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||||
|
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||||
|
//! transition if available.
|
||||||
|
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||||
|
//! This is a transitional state which can not be commanded.
|
||||||
|
//! The device is shut down and ready to be switched off.
|
||||||
|
//! After the command to set the switch off has been sent,
|
||||||
|
//! the mode changes to @c MODE_WAIT_OFF
|
||||||
|
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||||
|
//! This is a transitional state which can not be commanded. The device
|
||||||
|
//! will be switched on in this state. After the command to set the switch
|
||||||
|
//! on has been sent, the mode changes to @c MODE_WAIT_ON.
|
||||||
|
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||||
|
//! This is a transitional state which can not be commanded. The switch has
|
||||||
|
//! been commanded off and the handler waits for it to be off.
|
||||||
|
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||||
|
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||||
|
//! This is a transitional state which can not be commanded. The switch
|
||||||
|
//! has been commanded on and the handler waits for it to be on.
|
||||||
|
//! When the switch is on, the mode changes to @c MODE_TO_ON.
|
||||||
|
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||||
|
//! This is a transitional state which can not be commanded. The switch has
|
||||||
|
//! been commanded off and is off now. This state is only to do an RMAP
|
||||||
|
//! cycle once more where the doSendRead() function will set the mode to
|
||||||
|
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||||
|
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
||||||
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
|
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||||
@ -65,7 +109,6 @@ class DeviceHandlerIF {
|
|||||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
|
||||||
|
|
||||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||||
|
|
||||||
@ -136,10 +179,4 @@ class DeviceHandlerIF {
|
|||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThermalStateCfg {
|
|
||||||
lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID;
|
|
||||||
lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID;
|
|
||||||
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */
|
||||||
|
@ -7,21 +7,27 @@
|
|||||||
|
|
||||||
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
class DeviceHandlerThermalSet : public StaticLocalDataSet<2> {
|
||||||
public:
|
public:
|
||||||
DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg)
|
DeviceHandlerThermalSet(
|
||||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
|
HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||||
|
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||||
|
lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||||
|
: DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {}
|
||||||
|
|
||||||
DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
|
DeviceHandlerThermalSet(
|
||||||
: StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)),
|
object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID,
|
||||||
thermalStatePoolId(cfg.thermalStatePoolId),
|
lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
|
||||||
heaterRequestPoolId(cfg.thermalRequestPoolId) {}
|
lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID)
|
||||||
|
: StaticLocalDataSet(sid_t(deviceHandler, setId)),
|
||||||
|
thermalStatePoolId(thermalStateId),
|
||||||
|
heaterRequestPoolId(thermalStateRequestId) {}
|
||||||
|
|
||||||
const lp_id_t thermalStatePoolId;
|
const lp_id_t thermalStatePoolId;
|
||||||
const lp_id_t heaterRequestPoolId;
|
const lp_id_t heaterRequestPoolId;
|
||||||
|
|
||||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
lp_var_t<DeviceHandlerIF::dh_thermal_state_t> thermalState =
|
||||||
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(sid.objectId, thermalStatePoolId, this);
|
lp_var_t<DeviceHandlerIF::dh_thermal_state_t>(thermalStatePoolId, sid.objectId, this);
|
||||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
lp_var_t<DeviceHandlerIF::dh_heater_request_t> heaterRequest =
|
||||||
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(sid.objectId, heaterRequestPoolId, this);
|
lp_var_t<DeviceHandlerIF::dh_heater_request_t>(heaterRequestPoolId, sid.objectId, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||||
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||||
|
|
||||||
#include "fsfw/action/HasActionsIF.h"
|
#include "../action/HasActionsIF.h"
|
||||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
#include "../objectmanager/SystemObjectIF.h"
|
||||||
#include "fsfw/serialize/SerializeIF.h"
|
#include "../serialize/SerializeIF.h"
|
||||||
|
|
||||||
class DeviceTmReportingWrapper : public SerializeIF {
|
class DeviceTmReportingWrapper : public SerializeIF {
|
||||||
public:
|
public:
|
||||||
|
@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
|||||||
parentQueue(parentQueue),
|
parentQueue(parentQueue),
|
||||||
commandQueue(),
|
commandQueue(),
|
||||||
healthHelper(this, setObjectId) {
|
healthHelper(this, setObjectId) {
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
|
||||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||||
@ -29,10 +27,11 @@ ReturnValue_t HealthDevice::initialize() {
|
|||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (parentQueue != MessageQueueIF::NO_QUEUE) {
|
if (parentQueue != 0) {
|
||||||
return healthHelper.initialize(parentQueue);
|
return healthHelper.initialize(parentQueue);
|
||||||
|
} else {
|
||||||
|
return healthHelper.initialize();
|
||||||
}
|
}
|
||||||
return healthHelper.initialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); }
|
MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); }
|
||||||
|
@ -29,8 +29,10 @@ class HealthDevice : public SystemObject, public ExecutableObjectIF, public HasH
|
|||||||
protected:
|
protected:
|
||||||
HealthState lastHealth;
|
HealthState lastHealth;
|
||||||
|
|
||||||
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t parentQueue;
|
||||||
MessageQueueIF* commandQueue;
|
MessageQueueIF* commandQueue;
|
||||||
|
|
||||||
|
public:
|
||||||
HealthHelper healthHelper;
|
HealthHelper healthHelper;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,12 +15,11 @@ 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, uint32_t eventQueueDepth)
|
EventManager::EventManager(object_id_t setObjectId)
|
||||||
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
||||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
EventMessage::EVENT_MESSAGE_SIZE);
|
||||||
eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager::~EventManager() {
|
EventManager::~EventManager() {
|
||||||
@ -48,21 +47,9 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
|||||||
|
|
||||||
void EventManager::notifyListeners(EventMessage* message) {
|
void EventManager::notifyListeners(EventMessage* message) {
|
||||||
lockMutex();
|
lockMutex();
|
||||||
for (auto& listener : listenerList) {
|
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
|
||||||
if (listener.second.match(message)) {
|
if (iter->second.match(message)) {
|
||||||
ReturnValue_t result =
|
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
|
||||||
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 << " for event 0x" << std::setw(4)
|
|
||||||
<< message->getEventId() << " failed with result 0x" << std::setw(4) << result
|
|
||||||
<< std::setfill(' ') << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
|
||||||
listener.first, result);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlockMutex();
|
unlockMutex();
|
||||||
@ -213,19 +200,4 @@ 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,30 +21,30 @@ 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 DEFAULT_MAX_EVENTS_PER_CYCLE = 80;
|
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);
|
||||||
|
|
||||||
MessageQueueId_t getEventReportQueue();
|
MessageQueueId_t getEventReportQueue() override;
|
||||||
|
|
||||||
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
|
ReturnValue_t registerListener(MessageQueueId_t listener,
|
||||||
|
bool forwardAllButSelected = false) override;
|
||||||
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
|
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) override;
|
||||||
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
|
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) override;
|
||||||
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||||
EventId_t idTo = 0, bool idInverted = false,
|
EventId_t idTo = 0, bool idInverted = false,
|
||||||
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) override;
|
||||||
ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object);
|
ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) override;
|
||||||
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
ReturnValue_t unsubscribeFromEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||||
EventId_t idTo = 0, bool idInverted = false,
|
EventId_t idTo = 0, bool idInverted = false,
|
||||||
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) override;
|
||||||
ReturnValue_t performOperation(uint8_t opCode);
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
void printListeners();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MessageQueueIF* eventReportQueue = nullptr;
|
MessageQueueIF* eventReportQueue = nullptr;
|
||||||
|
@ -10,7 +10,7 @@ enum : uint8_t {
|
|||||||
CDH = 28,
|
CDH = 28,
|
||||||
TCS_1 = 59,
|
TCS_1 = 59,
|
||||||
PCDU_1 = 42,
|
PCDU_1 = 42,
|
||||||
POWER_SWITCH_IF = 43,
|
PCDU_2 = 43,
|
||||||
HEATER = 50,
|
HEATER = 50,
|
||||||
T_SENSORS = 52,
|
T_SENSORS = 52,
|
||||||
FDIR = 70,
|
FDIR = 70,
|
||||||
@ -33,7 +33,6 @@ enum : uint8_t {
|
|||||||
PUS_SERVICE_23 = 103,
|
PUS_SERVICE_23 = 103,
|
||||||
MGM_LIS3MDL = 106,
|
MGM_LIS3MDL = 106,
|
||||||
MGM_RM3100 = 107,
|
MGM_RM3100 = 107,
|
||||||
CFDP = 108,
|
|
||||||
|
|
||||||
FW_SUBSYSTEM_ID_RANGE
|
FW_SUBSYSTEM_ID_RANGE
|
||||||
};
|
};
|
||||||
|
@ -9,9 +9,8 @@
|
|||||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||||
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
eventQueue =
|
||||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
||||||
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FailureIsolationBase::~FailureIsolationBase() {
|
FailureIsolationBase::~FailureIsolationBase() {
|
||||||
@ -62,12 +61,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
|||||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||||
if (parentIF == nullptr) {
|
if (parentIF == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "FailureIsolationBase::intialize: Parent object "
|
sif::error << "FailureIsolationBase::intialize: Parent object"
|
||||||
<< "invalid" << std::endl;
|
<< "invalid." << std::endl;
|
||||||
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
#endif
|
||||||
#else
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
||||||
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
|
||||||
#endif
|
#endif
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
|
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
|
||||||
public:
|
public:
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||||
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
static const Event FDIR_CHANGED_STATE =
|
||||||
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
||||||
//! FDIR tries to restart device. Par1: event that caused recovery.
|
//!< (oldState) to par1 (newState).
|
||||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
||||||
//! FDIR turns off device. Par1: event that caused recovery.
|
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
||||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
||||||
|
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
||||||
|
|
||||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||||
|
@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
|
|||||||
parameterWrapper->set(faultCount);
|
parameterWrapper->set(faultCount);
|
||||||
break;
|
break;
|
||||||
case ParameterIds::TIMEOUT:
|
case ParameterIds::TIMEOUT:
|
||||||
parameterWrapper->set(timer.getTimeoutMs());
|
parameterWrapper->set(timer.timeout);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return INVALID_IDENTIFIER_ID;
|
return INVALID_IDENTIFIER_ID;
|
||||||
|
@ -40,7 +40,6 @@ class HasFileSystemIF {
|
|||||||
//! [EXPORT] : P1: Can be file system specific error code
|
//! [EXPORT] : P1: Can be file system specific error code
|
||||||
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
|
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
|
||||||
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
|
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
|
||||||
static constexpr ReturnValue_t FILESYSTEM_INACTIVE = MAKE_RETURN_CODE(2);
|
|
||||||
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
|
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
|
||||||
|
|
||||||
//! [EXPORT] : File system is currently busy
|
//! [EXPORT] : File system is currently busy
|
||||||
@ -74,12 +73,6 @@ class HasFileSystemIF {
|
|||||||
return MessageQueueIF::NO_QUEUE;
|
return MessageQueueIF::NO_QUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the base filename without the full directory path
|
|
||||||
virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen,
|
|
||||||
size_t& baseNameLen) = 0;
|
|
||||||
|
|
||||||
virtual bool isDirectory(const char* path) = 0;
|
|
||||||
|
|
||||||
virtual bool fileExists(FilesystemParams params) = 0;
|
virtual bool fileExists(FilesystemParams params) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +52,7 @@ ReturnValue_t DleParser::parseRingBuf(size_t& readSize) {
|
|||||||
// without skipping the STX
|
// without skipping the STX
|
||||||
readSize = vectorIdx;
|
readSize = vectorIdx;
|
||||||
ErrorInfo info;
|
ErrorInfo info;
|
||||||
|
info.len = vectorIdx;
|
||||||
setErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
|
setErrorContext(ErrorTypes::CONSECUTIVE_STX_CHARS, info);
|
||||||
return POSSIBLE_PACKET_LOSS;
|
return POSSIBLE_PACKET_LOSS;
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
class DleParser {
|
class DleParser {
|
||||||
public:
|
public:
|
||||||
//! [EXPORT] : [SKIP]
|
|
||||||
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
|
static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1);
|
||||||
//! [EXPORT] : [SKIP]
|
|
||||||
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
|
static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2);
|
||||||
|
|
||||||
using BufPair = std::pair<uint8_t*, size_t>;
|
using BufPair = std::pair<uint8_t*, size_t>;
|
||||||
|
|
||||||
enum class ContextType { NONE, PACKET_FOUND, ERROR };
|
enum class ContextType { NONE, PACKET_FOUND, ERROR };
|
||||||
|
@ -58,7 +58,7 @@ class Type : public SerializeIF {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct PodTypeConversion {
|
struct PodTypeConversion {
|
||||||
static_assert(not std::is_same<T, bool>::value,
|
static_assert(!std::is_same<T, bool>::value,
|
||||||
"Do not use boolean for the PoolEntry type, use uint8_t "
|
"Do not use boolean for the PoolEntry type, use uint8_t "
|
||||||
"instead! The ECSS standard defines a boolean as a one bit "
|
"instead! The ECSS standard defines a boolean as a one bit "
|
||||||
"field. Therefore it is preferred to store a boolean as an "
|
"field. Therefore it is preferred to store a boolean as an "
|
||||||
|
@ -37,16 +37,16 @@ void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void arrayprinter::printHex(const uint8_t *data, size_t size, size_t maxCharPerLine) {
|
void arrayprinter::printHex(const uint8_t *data, size_t datasize, size_t maxCharPerLine) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
if (sif::info.crAdditionEnabled()) {
|
if (sif::info.crAdditionEnabled()) {
|
||||||
std::cout << "\r" << std::endl;
|
std::cout << "\r" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "hex [" << std::setfill('0') << std::hex;
|
std::cout << "hex [" << std::setfill('0') << std::hex;
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < datasize; i++) {
|
||||||
std::cout << std::setw(2) << static_cast<int>(data[i]);
|
std::cout << std::setw(2) << static_cast<int>(data[i]);
|
||||||
if (i < size - 1) {
|
if (i < datasize - 1) {
|
||||||
std::cout << ",";
|
std::cout << ",";
|
||||||
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
if (i > 0 and (i + 1) % maxCharPerLine == 0) {
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@ -56,27 +56,11 @@ void arrayprinter::printHex(const uint8_t *data, size_t size, size_t maxCharPerL
|
|||||||
std::cout << std::dec << std::setfill(' ');
|
std::cout << std::dec << std::setfill(' ');
|
||||||
std::cout << "]" << std::endl;
|
std::cout << "]" << std::endl;
|
||||||
#else
|
#else
|
||||||
// General format: 0x01, 0x02, 0x03 so it is number of chars times 6
|
printf("hex [");
|
||||||
// plus line break plus small safety margin.
|
for (size_t i = 0; i < datasize; i++) {
|
||||||
char printBuffer[(size + 1) * 7 + 1] = {};
|
printf("0x%02x ", data[i]);
|
||||||
size_t currentPos = 0;
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
// To avoid buffer overflows.
|
|
||||||
if (sizeof(printBuffer) - currentPos <= 7) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPos += snprintf(printBuffer + currentPos, 6, "%02x", data[i]);
|
|
||||||
if (i < size - 1) {
|
|
||||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
|
||||||
if ((i + 1) % maxCharPerLine == 0) {
|
|
||||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#if FSFW_DISABLE_PRINTOUT == 0
|
printf("]\n");
|
||||||
printf("hex [%s]\n", printBuffer);
|
|
||||||
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,26 +84,10 @@ void arrayprinter::printDec(const uint8_t *data, size_t size, size_t maxCharPerL
|
|||||||
#else
|
#else
|
||||||
// General format: 32,243,-12 so it is number of chars times 4
|
// General format: 32,243,-12 so it is number of chars times 4
|
||||||
// plus line break plus small safety margin.
|
// plus line break plus small safety margin.
|
||||||
uint16_t expectedLines = ceil((double)size / maxCharPerLine);
|
|
||||||
char printBuffer[size * 4 + 1 + expectedLines] = {};
|
|
||||||
size_t currentPos = 0;
|
|
||||||
for (size_t i = 0; i < size; i++) {
|
|
||||||
// To avoid buffer overflows.
|
|
||||||
if (sizeof(printBuffer) - currentPos <= 4) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPos += snprintf(printBuffer + currentPos, 4, "%d", data[i]);
|
for (size_t i = 0; i < size; i++) {
|
||||||
if (i < size - 1) {
|
// TODO
|
||||||
currentPos += sprintf(printBuffer + currentPos, ",");
|
|
||||||
if ((i + 1) % maxCharPerLine == 0) {
|
|
||||||
currentPos += sprintf(printBuffer + currentPos, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#if FSFW_DISABLE_PRINTOUT == 0
|
|
||||||
printf("dec [%s]\n", printBuffer);
|
|
||||||
#endif /* FSFW_DISABLE_PRINTOUT == 0 */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +53,8 @@ class VectorOperations {
|
|||||||
mulScalar(vector, 1 / norm(vector, size), normalizedVector, size);
|
mulScalar(vector, 1 / norm(vector, size), normalizedVector, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||||
T max = vector[size - 1];
|
T max = -1;
|
||||||
uint8_t foundIndex = size - 1;
|
|
||||||
|
|
||||||
for (; size > 0; size--) {
|
for (; size > 0; size--) {
|
||||||
T abs = vector[size - 1];
|
T abs = vector[size - 1];
|
||||||
@ -65,35 +64,24 @@ class VectorOperations {
|
|||||||
if (abs > max) {
|
if (abs > max) {
|
||||||
max = abs;
|
max = abs;
|
||||||
if (index != 0) {
|
if (index != 0) {
|
||||||
foundIndex = size - 1;
|
*index = size - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != nullptr) {
|
|
||||||
*index = foundIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
static T maxValue(const T *vector, uint8_t size, uint8_t *index = nullptr) {
|
static T maxValue(const T *vector, uint8_t size, uint8_t *index = 0) {
|
||||||
T max = vector[size - 1];
|
T max = -1;
|
||||||
uint8_t foundIndex = size - 1;
|
|
||||||
|
|
||||||
for (; size > 0; size--) {
|
for (; size > 0; size--) {
|
||||||
if (vector[size - 1] > max) {
|
if (vector[size - 1] > max) {
|
||||||
max = vector[size - 1];
|
max = vector[size - 1];
|
||||||
if (index != 0) {
|
if (index != 0) {
|
||||||
foundIndex = size - 1;
|
*index = size - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != nullptr) {
|
|
||||||
*index = foundIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,24 +16,26 @@ 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 constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
|
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||||
static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
|
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(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);
|
||||||
//! Assembly overwrites health information of children to keep satellite alive.
|
static const Event OVERWRITING_HEALTH =
|
||||||
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
||||||
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
//!< satellite alive.
|
||||||
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
static const Event TRYING_RECOVERY =
|
||||||
//! Recovery is ongoing. Comes twice during recovery.
|
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
||||||
//! P1: 0 for the first, 1 for the second event. P2: 0
|
//!< power-cycle). No parameters.
|
||||||
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
static const Event RECOVERY_STEP =
|
||||||
//! Recovery was completed. Not necessarily successful. No parameters.
|
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
||||||
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
//!< 0 for the first, 1 for the second event. P2: 0
|
||||||
|
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;
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
#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;
|
||||||
|
@ -55,7 +55,7 @@ class HousekeepingSnapshot : public SerializeIF {
|
|||||||
: 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,
|
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||||
Endianness streamEndianness) const {
|
Endianness streamEndianness) const override {
|
||||||
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
|
||||||
here. */
|
here. */
|
||||||
@ -70,7 +70,7 @@ class HousekeepingSnapshot : public SerializeIF {
|
|||||||
return updateData->serialize(buffer, size, maxSize, streamEndianness);
|
return updateData->serialize(buffer, size, maxSize, streamEndianness);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
virtual size_t getSerializedSize() const override {
|
||||||
if (updateData == nullptr) {
|
if (updateData == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3,37 +3,85 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#include "fsfw/datapoollocal/LocalPoolDataSetBase.h"
|
#include "fsfw/datapoollocal/LocalPoolDataSetBase.h"
|
||||||
#include "fsfw/serviceinterface.h"
|
|
||||||
|
|
||||||
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner)
|
PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner)
|
||||||
: owner(owner) {}
|
: owner(owner) {}
|
||||||
|
|
||||||
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
void PeriodicHousekeepingHelper::initialize(float collectionInterval,
|
||||||
dur_millis_t minimumPeriodicInterval) {
|
dur_millis_t minimumPeriodicInterval,
|
||||||
|
uint8_t nonDiagIntervalFactor) {
|
||||||
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
this->minimumPeriodicInterval = minimumPeriodicInterval;
|
||||||
changeCollectionInterval(collectionInterval);
|
this->nonDiagIntervalFactor = nonDiagIntervalFactor;
|
||||||
|
collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval);
|
||||||
|
/* This will cause a checkOpNecessary call to be true immediately. I think it's okay
|
||||||
|
if a HK packet is generated immediately instead of waiting one generation cycle. */
|
||||||
|
internalTickCounter = collectionIntervalTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
|
float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const {
|
||||||
return collectionInterval;
|
return intervalTicksToSeconds(collectionIntervalTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
bool PeriodicHousekeepingHelper::checkOpNecessary() {
|
||||||
if (hkGenerationCd.hasTimedOut()) {
|
if (internalTickCounter >= collectionIntervalTicks) {
|
||||||
hkGenerationCd.resetTimer();
|
internalTickCounter = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
internalTickCounter++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
|
uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks(
|
||||||
uint32_t intervalMs = newIntervalSeconds * 1000;
|
float collectionIntervalSeconds) {
|
||||||
if (newIntervalSeconds <= 0) {
|
if (owner == nullptr) {
|
||||||
intervalMs = minimumPeriodicInterval;
|
return 0;
|
||||||
newIntervalSeconds = static_cast<float>(minimumPeriodicInterval) / 1000.0;
|
}
|
||||||
|
bool isDiagnostics = owner->isDiagnostics();
|
||||||
|
|
||||||
|
/* Avoid division by zero */
|
||||||
|
if (minimumPeriodicInterval == 0) {
|
||||||
|
if (isDiagnostics) {
|
||||||
|
/* Perform operation each cycle */
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dur_millis_t intervalInMs = collectionIntervalSeconds * 1000;
|
||||||
|
uint32_t divisor = minimumPeriodicInterval;
|
||||||
|
if (not isDiagnostics) {
|
||||||
|
/* We need to multiply the divisor because non-diagnostics only
|
||||||
|
allow a multiple of the minimum periodic interval */
|
||||||
|
divisor *= nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
uint32_t ticks = std::ceil(static_cast<float>(intervalInMs) / divisor);
|
||||||
|
if (not isDiagnostics) {
|
||||||
|
/* Now we need to multiply the calculated ticks with the factor as as well
|
||||||
|
because the minimum tick count to generate a non-diagnostic is the factor itself.
|
||||||
|
|
||||||
|
Example calculation for non-diagnostic with
|
||||||
|
0.4 second interval and 0.2 second task interval.
|
||||||
|
Resultant tick count of 5 is equal to operation each second.
|
||||||
|
|
||||||
|
Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second
|
||||||
|
task interval.
|
||||||
|
Resultant tick count of 10 is equal to operatin every 2 seconds.
|
||||||
|
|
||||||
|
Example calculation for diagnostic with 0.4 second interval and 0.3
|
||||||
|
second task interval. Resulting tick count of 2 is equal to operation
|
||||||
|
every 0.6 seconds. */
|
||||||
|
ticks *= nonDiagIntervalFactor;
|
||||||
|
}
|
||||||
|
return ticks;
|
||||||
}
|
}
|
||||||
collectionInterval = newIntervalSeconds;
|
}
|
||||||
hkGenerationCd.setTimeout(intervalMs);
|
|
||||||
// We want an immediate HK packet at the start, so time out the generation CD immediately.
|
float PeriodicHousekeepingHelper::intervalTicksToSeconds(uint32_t collectionInterval) const {
|
||||||
hkGenerationCd.timeOut();
|
/* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get
|
||||||
|
the value in seconds */
|
||||||
|
return static_cast<float>(collectionInterval * minimumPeriodicInterval / 1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) {
|
||||||
|
collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include "fsfw/timemanager/Clock.h"
|
#include "fsfw/timemanager/Clock.h"
|
||||||
#include "fsfw/timemanager/Countdown.h"
|
|
||||||
|
|
||||||
class LocalPoolDataSetBase;
|
class LocalPoolDataSetBase;
|
||||||
|
|
||||||
@ -12,7 +11,8 @@ class PeriodicHousekeepingHelper {
|
|||||||
public:
|
public:
|
||||||
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner);
|
||||||
|
|
||||||
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||||
|
uint8_t nonDiagIntervalFactor);
|
||||||
|
|
||||||
void changeCollectionInterval(float newInterval);
|
void changeCollectionInterval(float newInterval);
|
||||||
float getCollectionIntervalInSeconds() const;
|
float getCollectionIntervalInSeconds() const;
|
||||||
@ -20,10 +20,14 @@ class PeriodicHousekeepingHelper {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
LocalPoolDataSetBase* owner = nullptr;
|
LocalPoolDataSetBase* owner = nullptr;
|
||||||
Countdown hkGenerationCd;
|
uint8_t nonDiagIntervalFactor = 0;
|
||||||
float collectionInterval = 0.0;
|
|
||||||
|
uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds);
|
||||||
|
float intervalTicksToSeconds(uint32_t collectionInterval) const;
|
||||||
|
|
||||||
dur_millis_t minimumPeriodicInterval = 0;
|
dur_millis_t minimumPeriodicInterval = 0;
|
||||||
|
uint32_t internalTickCounter = 1;
|
||||||
|
uint32_t collectionIntervalTicks = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */
|
#endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */
|
||||||
|
@ -5,19 +5,13 @@
|
|||||||
#include "fsfw/ipc/QueueFactory.h"
|
#include "fsfw/ipc/QueueFactory.h"
|
||||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
|
||||||
bool enableSetByDefault, float generationFrequency)
|
|
||||||
: SystemObject(setObjectId),
|
: SystemObject(setObjectId),
|
||||||
|
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
|
||||||
poolManager(this, commandQueue),
|
poolManager(this, commandQueue),
|
||||||
enableSetByDefault(enableSetByDefault),
|
|
||||||
generationFrequency(generationFrequency),
|
|
||||||
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();
|
||||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
|
||||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
|
||||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InternalErrorReporter::~InternalErrorReporter() {
|
InternalErrorReporter::~InternalErrorReporter() {
|
||||||
@ -45,14 +39,15 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
|||||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
sif::debug << "InternalErrorReporter::performOperation: Errors "
|
||||||
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
<< "occured!" << std::endl;
|
||||||
<< newStoreHits << std::endl;
|
sif::debug << "Queue errors: " << newQueueHits << std::endl;
|
||||||
|
sif::debug << "TM errors: " << newTmHits << std::endl;
|
||||||
|
sif::debug << "Store errors: " << newStoreHits << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printDebug(
|
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||||
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||||
"| %lu\n",
|
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||||
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||||
static_cast<unsigned int>(newStoreHits));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,8 +132,9 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool
|
|||||||
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
|
localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry);
|
||||||
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
|
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry);
|
||||||
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
|
localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry);
|
||||||
poolManager.subscribeForRegularPeriodicPacket(
|
poolManager.subscribeForDiagPeriodicPacket(subdp::DiagnosticsHkPeriodicParams(
|
||||||
subdp::RegularHkPeriodicParams(internalErrorSid, enableSetByDefault, generationFrequency));
|
internalErrorSid, false,
|
||||||
|
static_cast<float>(getPeriodicOperationFrequency()) / static_cast<float>(1000.0)));
|
||||||
internalErrorDataset.setValidity(true, true);
|
internalErrorDataset.setValidity(true, true);
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,7 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
public InternalErrorReporterIF,
|
public InternalErrorReporterIF,
|
||||||
public HasLocalDataPoolIF {
|
public HasLocalDataPoolIF {
|
||||||
public:
|
public:
|
||||||
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth,
|
InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5);
|
||||||
bool enableSetByDefault, float generationFrequency);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable diagnostic printout. Please note that this feature will
|
* Enable diagnostic printout. Please note that this feature will
|
||||||
@ -64,8 +63,6 @@ class InternalErrorReporter : public SystemObject,
|
|||||||
MutexIF* mutex = nullptr;
|
MutexIF* mutex = nullptr;
|
||||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
uint32_t timeoutMs = 20;
|
uint32_t timeoutMs = 20;
|
||||||
bool enableSetByDefault;
|
|
||||||
float generationFrequency;
|
|
||||||
|
|
||||||
sid_t internalErrorSid;
|
sid_t internalErrorSid;
|
||||||
InternalErrorDataset internalErrorDataset;
|
InternalErrorDataset internalErrorDataset;
|
||||||
|
@ -34,7 +34,7 @@ class CommandMessageIF {
|
|||||||
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
||||||
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
||||||
//! Reply indicating that the current command was rejected,
|
//! Reply indicating that the current command was rejected,
|
||||||
//! Parameter 1 should contain the error code
|
//! par1 should contain the error code
|
||||||
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
||||||
|
|
||||||
virtual ~CommandMessageIF(){};
|
virtual ~CommandMessageIF(){};
|
||||||
|
@ -7,17 +7,14 @@
|
|||||||
class MutexGuard {
|
class MutexGuard {
|
||||||
public:
|
public:
|
||||||
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
|
MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING,
|
||||||
uint32_t timeoutMs = 0, const char* context = nullptr)
|
uint32_t timeoutMs = 0)
|
||||||
: internalMutex(mutex) {
|
: internalMutex(mutex) {
|
||||||
if (context == nullptr) {
|
|
||||||
context = "unknown";
|
|
||||||
}
|
|
||||||
if (mutex == nullptr) {
|
if (mutex == nullptr) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MutexGuard::" << context << ": Passed mutex is invalid!" << std::endl;
|
sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("MutexGuard::%s: Passed mutex is invalid!\n", context);
|
sif::printError("MutexGuard: Passed mutex is invalid!\n");
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
return;
|
return;
|
||||||
@ -26,11 +23,11 @@ class MutexGuard {
|
|||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
if (result == MutexIF::MUTEX_TIMEOUT) {
|
if (result == MutexIF::MUTEX_TIMEOUT) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of "
|
sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs
|
||||||
<< timeoutMs << " milliseconds!" << std::endl;
|
<< " milliseconds!" << std::endl;
|
||||||
#else
|
#else
|
||||||
sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n",
|
sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n",
|
||||||
context, timeoutMs);
|
timeoutMs);
|
||||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
} else if (result != returnvalue::OK) {
|
} else if (result != returnvalue::OK) {
|
||||||
|
@ -19,33 +19,32 @@ class HasModesIF {
|
|||||||
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
|
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
|
||||||
|
|
||||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
|
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
|
||||||
//! An object announces changing the mode. p1: target mode. p2: target submode
|
static const Event CHANGING_MODE =
|
||||||
static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
|
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
|
||||||
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
|
//!< p2: target submode
|
||||||
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
|
static const Event MODE_INFO = MAKE_EVENT(
|
||||||
|
1,
|
||||||
|
severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||||
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
|
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
|
||||||
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
|
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||||
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
|
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
|
||||||
//! Indicates a bug or configuration failure: Object is in a mode it should never be in.
|
static const Event OBJECT_IN_INVALID_MODE =
|
||||||
static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
|
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
|
||||||
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
|
//!< mode it should never be in.
|
||||||
//! p1: target mode. p2: target submode
|
static const Event FORCING_MODE = MAKE_EVENT(
|
||||||
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
|
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
|
||||||
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
|
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
|
||||||
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
|
static const Event MODE_CMD_REJECTED =
|
||||||
|
MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
|
||||||
|
//!< called object id, Par2: return code.
|
||||||
|
|
||||||
//! The device is powered and ready to perform operations. In this mode, no commands are
|
static const Mode_t MODE_ON =
|
||||||
//! sent by the device handler itself, but direct commands van be commanded and will be
|
1; //!< The device is powered and ready to perform operations. In this mode, no commands are
|
||||||
//! interpreted
|
//!< sent by the device handler itself, but direct commands van be commanded and will be
|
||||||
static constexpr Mode_t MODE_ON = 1;
|
//!< interpreted
|
||||||
//! The device is powered off. The only command accepted in this mode is a mode change to on.
|
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
|
||||||
static constexpr Mode_t MODE_OFF = 0;
|
//!< this mode is a mode change to on.
|
||||||
|
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
|
||||||
static constexpr Mode_t MODE_INVALID = -1;
|
|
||||||
static constexpr Mode_t MODE_UNDEFINED = -2;
|
|
||||||
|
|
||||||
//! To avoid checks against magic number "0".
|
|
||||||
static const Submode_t SUBMODE_NONE = 0;
|
|
||||||
|
|
||||||
virtual ~HasModesIF() {}
|
virtual ~HasModesIF() {}
|
||||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||||
|
@ -24,19 +24,3 @@ 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); }
|
|
||||||
|
@ -1,42 +1,43 @@
|
|||||||
#ifndef FSFW_MODES_MODEMESSAGE_H_
|
#ifndef FSFW_MODES_MODEMESSAGE_H_
|
||||||
#define FSFW_MODES_MODEMESSAGE_H_
|
#define FSFW_MODES_MODEMESSAGE_H_
|
||||||
|
|
||||||
#include "fsfw/ipc/CommandMessage.h"
|
#include "../ipc/CommandMessage.h"
|
||||||
|
|
||||||
typedef uint32_t Mode_t;
|
typedef uint32_t Mode_t;
|
||||||
typedef uint8_t Submode_t;
|
typedef uint8_t Submode_t;
|
||||||
|
|
||||||
class ModeMessage {
|
class ModeMessage {
|
||||||
|
private:
|
||||||
|
ModeMessage();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
||||||
//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
static const Command_t CMD_MODE_COMMAND =
|
||||||
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||||
//! as this will break the subsystem mode machine!!
|
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||||
static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);
|
//! as this will break the subsystem mode machine!!
|
||||||
//!> Command to set the specified Mode, regardless of external control flag, replies
|
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
|
||||||
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
|
||||||
//! replies, as this will break the subsystem mode machine!!
|
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);
|
//! replies, as this will break the subsystem mode machine!!
|
||||||
//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
static const Command_t REPLY_MODE_REPLY =
|
||||||
static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);
|
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||||
//!> Unrequested info about the current mode (used for composites to
|
static const Command_t REPLY_MODE_INFO =
|
||||||
//! inform their container of a changed mode)
|
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
|
||||||
static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03);
|
//! inform their container of a changed mode)
|
||||||
//!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
|
||||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04);
|
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||||
//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
static const Command_t REPLY_WRONG_MODE_REPLY =
|
||||||
//! and a transition started but was aborted; the parameters contain
|
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||||
//! the mode that was reached
|
//! and a transition started but was aborted; the parameters contain
|
||||||
static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);
|
//! the mode that was reached
|
||||||
//!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
|
||||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);
|
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||||
//!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
|
||||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);
|
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||||
//!> Command to trigger an ModeInfo Event and to send this command to
|
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
|
||||||
//! every child. This command does NOT have a reply.
|
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
|
||||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = MAKE_COMMAND_ID(0x08);
|
//! every child. This command does NOT have a reply.
|
||||||
|
|
||||||
ModeMessage() = delete;
|
|
||||||
|
|
||||||
static Mode_t getMode(const CommandMessage* message);
|
static Mode_t getMode(const CommandMessage* message);
|
||||||
static Submode_t getSubmode(const CommandMessage* message);
|
static Submode_t getSubmode(const CommandMessage* message);
|
||||||
@ -44,9 +45,6 @@ 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);
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,7 @@ class AbsLimitMonitor : public MonitorBase<T> {
|
|||||||
violationEvent(violationEvent),
|
violationEvent(violationEvent),
|
||||||
aboveIsViolation(aboveIsViolation) {}
|
aboveIsViolation(aboveIsViolation) {}
|
||||||
virtual ~AbsLimitMonitor() {}
|
virtual ~AbsLimitMonitor() {}
|
||||||
virtual ReturnValue_t checkSample(T sample, T *crossedLimit) {
|
ReturnValue_t checkSample(T sample, T *crossedLimit) override {
|
||||||
*crossedLimit = limit;
|
*crossedLimit = limit;
|
||||||
if (aboveIsViolation) {
|
if (aboveIsViolation) {
|
||||||
if ((std::abs(sample) > limit)) {
|
if ((std::abs(sample) > limit)) {
|
||||||
@ -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,
|
||||||
@ -61,7 +61,7 @@ class AbsLimitMonitor : public MonitorBase<T> {
|
|||||||
void setLimit(T value) { limit = value; }
|
void setLimit(T value) { limit = value; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void sendTransitionEvent(T currentValue, ReturnValue_t state) {
|
void sendTransitionEvent(T currentValue, ReturnValue_t state) override {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case MonitoringIF::OUT_OF_RANGE:
|
case MonitoringIF::OUT_OF_RANGE:
|
||||||
EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->globalPoolId.objectId,
|
EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->globalPoolId.objectId,
|
||||||
|
@ -109,16 +109,13 @@ void ObjectManager::initialize() {
|
|||||||
for (auto const& it : objectList) {
|
for (auto const& it : objectList) {
|
||||||
result = it.second->initialize();
|
result = it.second->initialize();
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
#if FSFW_VERBOSE_LEVEL >= 1
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
object_id_t var = it.first;
|
||||||
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
|
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
|
||||||
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
|
<< std::setfill('0') << var
|
||||||
<< std::dec << std::setfill(' ') << std::endl;
|
<< " failed to "
|
||||||
#else
|
"initialize with code 0x"
|
||||||
sif::printError(
|
<< result << std::dec << std::setfill(' ') << std::endl;
|
||||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
|
|
||||||
it.first);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
errorCount++;
|
errorCount++;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ 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,
|
||||||
|
@ -18,10 +18,7 @@ elseif(FSFW_OSAL MATCHES "host")
|
|||||||
endif()
|
endif()
|
||||||
set(FSFW_OSAL_HOST 1)
|
set(FSFW_OSAL_HOST 1)
|
||||||
else()
|
else()
|
||||||
message(
|
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
||||||
WARNING
|
|
||||||
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
|
||||||
|
|
||||||
# Not set. Assumuing this is a host build, try to determine host OS
|
# Not set. Assumuing this is a host build, try to determine host OS
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_subdirectory(host)
|
add_subdirectory(host)
|
||||||
|
@ -24,8 +24,11 @@
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <windows.h>
|
// Thanks, windows
|
||||||
|
// clang-format off
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
// clang-format on
|
||||||
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
|
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
|
||||||
#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN
|
#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN
|
||||||
#else
|
#else
|
||||||
|
@ -41,7 +41,6 @@ int TcpIpBase::closeSocket(socket_t socket) {
|
|||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
return close(socket);
|
return close(socket);
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TcpIpBase::getLastSocketError() {
|
int TcpIpBase::getLastSocketError() {
|
||||||
@ -50,5 +49,4 @@ int TcpIpBase::getLastSocketError() {
|
|||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
return errno;
|
return errno;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId,
|
||||||
uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId)
|
object_id_t tcStoreId)
|
||||||
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
: TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, 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, uint32_t msgQueueDepth,
|
TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
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();
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#ifdef PLATFORM_WIN
|
#ifdef PLATFORM_WIN
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
typedef SSIZE_T ssize_t;
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
@ -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,
|
||||||
TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize,
|
size_t receptionBufferSize, size_t ringBufferSize,
|
||||||
size_t ringBufferSize, ReceptionModes receptionMode)
|
std::string customTcpServerPort, ReceptionModes receptionMode)
|
||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
tmtcBridgeId(tmtcTcpBridge),
|
tmtcBridgeId(tmtcTcpBridge),
|
||||||
receptionMode(receptionMode),
|
receptionMode(receptionMode),
|
||||||
tcpConfig(cfg),
|
tcpConfig(std::move(customTcpServerPort)),
|
||||||
receptionBuffer(receptionBufferSize),
|
receptionBuffer(receptionBufferSize),
|
||||||
ringBuffer(ringBufferSize, true) {}
|
ringBuffer(ringBufferSize, true) {}
|
||||||
|
|
||||||
@ -91,15 +91,6 @@ 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) {
|
||||||
@ -283,8 +274,6 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
|||||||
ConstStorageAccessor storeAccessor(storeId);
|
ConstStorageAccessor storeAccessor(storeId);
|
||||||
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
|
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
// Invalid entry, pop FIFO
|
|
||||||
tmtcBridge->tmFifo->pop();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (wiretappingEnabled) {
|
if (wiretappingEnabled) {
|
||||||
|
@ -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:
|
||||||
TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {}
|
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
||||||
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,25 +63,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
*/
|
*/
|
||||||
int tcpTmFlags = 0;
|
int tcpTmFlags = 0;
|
||||||
|
|
||||||
std::string tcpPort = DEFAULT_SERVER_PORT;
|
const std::string tcpPort;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
||||||
|
|
||||||
static constexpr size_t ETHERNET_MTU_SIZE = 1500;
|
static constexpr size_t ETHERNET_MTU_SIZE = 1500;
|
||||||
@ -96,9 +80,10 @@ 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::TcpConfig cfg,
|
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||||
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;
|
||||||
|
|
||||||
@ -131,7 +116,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
|||||||
|
|
||||||
ReceptionModes receptionMode;
|
ReceptionModes receptionMode;
|
||||||
TcpConfig tcpConfig;
|
TcpConfig tcpConfig;
|
||||||
struct sockaddr tcpAddress = {};
|
// struct sockaddr tcpAddress = {};
|
||||||
socket_t listenerTcpSocket = 0;
|
socket_t listenerTcpSocket = 0;
|
||||||
|
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#ifdef PLATFORM_WIN
|
#ifdef PLATFORM_WIN
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#ifdef PLATFORM_WIN
|
#ifdef PLATFORM_WIN
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
#elif defined(PLATFORM_UNIX)
|
#elif defined(PLATFORM_UNIX)
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
@ -20,9 +21,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,
|
||||||
uint32_t msgQueueDepth, const std::string &udpServerPort_,
|
const std::string &udpServerPort_, object_id_t tmStoreId,
|
||||||
object_id_t tmStoreId, object_id_t tcStoreId)
|
object_id_t tcStoreId)
|
||||||
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) {
|
: TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
if (udpServerPort_.empty()) {
|
if (udpServerPort_.empty()) {
|
||||||
udpServerPort = DEFAULT_SERVER_PORT;
|
udpServerPort = DEFAULT_SERVER_PORT;
|
||||||
} else {
|
} else {
|
||||||
@ -126,7 +127,10 @@ 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 << " bytes were sent" << std::endl;
|
sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent
|
||||||
|
<< " 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, uint32_t msgQueueDepth,
|
UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
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;
|
||||||
|
@ -40,7 +40,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF {
|
|||||||
void refreshTaskHandle();
|
void refreshTaskHandle();
|
||||||
|
|
||||||
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
||||||
uint32_t timeoutMs = portMAX_DELAY) override;
|
uint32_t timeoutMs = 0) override;
|
||||||
ReturnValue_t release() override;
|
ReturnValue_t release() override;
|
||||||
uint8_t getSemaphoreCounter() const override;
|
uint8_t getSemaphoreCounter() const override;
|
||||||
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
|
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
|
||||||
|
@ -51,7 +51,7 @@ class BinarySemaphore : public SemaphoreIF {
|
|||||||
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
|
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
|
||||||
*/
|
*/
|
||||||
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
||||||
uint32_t timeoutMs = portMAX_DELAY) override;
|
uint32_t timeoutMs = 0) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
|
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
|
||||||
|
@ -11,19 +11,6 @@
|
|||||||
// TODO sanitize input?
|
// TODO sanitize input?
|
||||||
// TODO much of this code can be reused for tick-only systems
|
// TODO much of this code can be reused for tick-only systems
|
||||||
|
|
||||||
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
|
|
||||||
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return setClock(&time_timeval);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::setClock(const timeval* time) {
|
ReturnValue_t Clock::setClock(const timeval* time) {
|
||||||
timeval uptime = getUptime();
|
timeval uptime = getUptime();
|
||||||
|
|
||||||
@ -44,81 +31,12 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
|
||||||
*uptime = getUptime();
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeval Clock::getUptime() {
|
timeval Clock::getUptime() {
|
||||||
TickType_t ticksSinceStart = xTaskGetTickCount();
|
TickType_t ticksSinceStart = xTaskGetTickCount();
|
||||||
return Timekeeper::ticksToTimeval(ticksSinceStart);
|
return Timekeeper::ticksToTimeval(ticksSinceStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
|
|
||||||
timeval uptime = getUptime();
|
|
||||||
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint32_t Clock::getUptimeSeconds() {
|
// uint32_t Clock::getUptimeSeconds() {
|
||||||
// timeval uptime = getUptime();
|
// timeval uptime = getUptime();
|
||||||
// return uptime.tv_sec;
|
// return uptime.tv_sec;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
ReturnValue_t result = getClock_timeval(&time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
|
|
||||||
timeval time_timeval;
|
|
||||||
ReturnValue_t result = getClock_timeval(&time_timeval);
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
struct tm time_tm;
|
|
||||||
|
|
||||||
gmtime_r(&time_timeval.tv_sec, &time_tm);
|
|
||||||
|
|
||||||
time->year = time_tm.tm_year + 1900;
|
|
||||||
time->month = time_tm.tm_mon + 1;
|
|
||||||
time->day = time_tm.tm_mday;
|
|
||||||
|
|
||||||
time->hour = time_tm.tm_hour;
|
|
||||||
time->minute = time_tm.tm_min;
|
|
||||||
time->second = time_tm.tm_sec;
|
|
||||||
|
|
||||||
time->usecond = time_timeval.tv_usec;
|
|
||||||
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
|
|
||||||
struct tm time_tm = {};
|
|
||||||
|
|
||||||
time_tm.tm_year = from->year - 1900;
|
|
||||||
time_tm.tm_mon = from->month - 1;
|
|
||||||
time_tm.tm_mday = from->day;
|
|
||||||
|
|
||||||
time_tm.tm_hour = from->hour;
|
|
||||||
time_tm.tm_min = from->minute;
|
|
||||||
time_tm.tm_sec = from->second;
|
|
||||||
|
|
||||||
time_t seconds = mktime(&time_tm);
|
|
||||||
|
|
||||||
to->tv_sec = seconds;
|
|
||||||
to->tv_usec = from->usecond;
|
|
||||||
// Fails in 2038..
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
|
|
||||||
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
|
|
||||||
return returnvalue::OK;
|
|
||||||
}
|
|
||||||
|
@ -34,7 +34,7 @@ class CountingSemaphoreUsingTask : public SemaphoreIF {
|
|||||||
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
|
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
|
||||||
*/
|
*/
|
||||||
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
|
||||||
uint32_t timeoutMs = portMAX_DELAY) override;
|
uint32_t timeoutMs = 0) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release a semaphore, increasing the number of available counting
|
* Release a semaphore, increasing the number of available counting
|
||||||
|
@ -56,7 +56,9 @@ ReturnValue_t FixedTimeslotTask::startTask() {
|
|||||||
// start time for the first entry.
|
// start time for the first entry.
|
||||||
auto slotListIter = pollingSeqTable.current;
|
auto slotListIter = pollingSeqTable.current;
|
||||||
|
|
||||||
pollingSeqTable.intializeSequenceAfterTaskCreation();
|
ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
|
||||||
|
// Ignore returnvalue for now
|
||||||
|
static_cast<void>(result);
|
||||||
|
|
||||||
// The start time for the first entry is read.
|
// The start time for the first entry is read.
|
||||||
uint32_t intervalMs = slotListIter->pollingTimeMs;
|
uint32_t intervalMs = slotListIter->pollingTimeMs;
|
||||||
|
@ -22,7 +22,7 @@ ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
|
|||||||
return MutexIF::MUTEX_NOT_FOUND;
|
return MutexIF::MUTEX_NOT_FOUND;
|
||||||
}
|
}
|
||||||
// If the timeout type is BLOCKING, this will be the correct value.
|
// If the timeout type is BLOCKING, this will be the correct value.
|
||||||
uint32_t timeout = portMAX_DELAY;
|
TickType_t timeout = portMAX_DELAY;
|
||||||
if (timeoutType == TimeoutType::POLLING) {
|
if (timeoutType == TimeoutType::POLLING) {
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
} else if (timeoutType == TimeoutType::WAITING) {
|
} else if (timeoutType == TimeoutType::WAITING) {
|
||||||
|
@ -3,16 +3,16 @@
|
|||||||
void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); }
|
void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); }
|
||||||
|
|
||||||
void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::TASK) {
|
void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::TASK) {
|
||||||
if (callContext == CallContext::ISR) {
|
// if (callContext == CallContext::ISR) {
|
||||||
// This function depends on the partmacro.h definition for the specific device
|
// // This function depends on the partmacro.h definition for the specific device
|
||||||
vRequestContextSwitchFromISR();
|
// vRequestContextSwitchFromISR();
|
||||||
} else {
|
// } else {
|
||||||
vRequestContextSwitchFromTask();
|
vRequestContextSwitchFromTask();
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); }
|
TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); }
|
||||||
|
|
||||||
size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) {
|
// size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) {
|
||||||
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
|
// return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
|
||||||
}
|
// }
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Architecture dependant portmacro.h function call.
|
* Architecture dependant portmacro.h function call.
|
||||||
* Should be implemented in bsp.
|
* Should be implemented in bsp.
|
||||||
*/
|
*/
|
||||||
extern "C" void vRequestContextSwitchFromISR();
|
// extern "C" void vRequestContextSwitchFromISR();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Used by functions to tell if they are being called from
|
* Used by functions to tell if they are being called from
|
||||||
@ -53,7 +53,7 @@ TaskHandle_t getCurrentTaskHandle();
|
|||||||
* @return Smallest value of stack remaining since the task was started in
|
* @return Smallest value of stack remaining since the task was started in
|
||||||
* words.
|
* words.
|
||||||
*/
|
*/
|
||||||
size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr);
|
// size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr);
|
||||||
|
|
||||||
}; // namespace TaskManagement
|
}; // namespace TaskManagement
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user