Compare commits

..

115 Commits

Author SHA1 Message Date
7426e10f82 clocks suck a little less 2023-01-26 11:33:40 +01:00
uli
123c81777a clocks suck 2023-01-26 00:01:40 +01:00
6d85fa155e cleaning up unittest build 2023-01-20 16:05:04 +01:00
e6af6200ae updating CI 2023-01-19 17:32:23 +01:00
5ca3e83934 working on rtems CI build 2023-01-19 16:46:43 +01:00
6adabb059a fixing rtems cmake config 2023-01-19 16:27:10 +01:00
5d0a5cd201 exiting qemu nonzero when tests fail 2023-01-19 14:47:40 +01:00
adb8483bb0 unittests for rtems working 2023-01-19 14:24:33 +01:00
fdfdce2fb0 compiling, crashing when run 2023-01-18 00:25:25 +01:00
90efb132d0 fixing rebase error 2023-01-16 12:41:23 +01:00
fe9804d922 format 2023-01-16 12:35:14 +01:00
a0eae66c35 checking if this helps docker build 2023-01-16 12:32:16 +01:00
e131480d5f two errors found by valgrind 2023-01-16 12:32:15 +01:00
90bafbb6de typos in Jenkinsfile 2023-01-16 12:31:54 +01:00
47d85fb61c finished freertos unittests, valgrind not happy yet 2023-01-16 12:31:53 +01:00
39dad5f45b unittests running but failing 2023-01-16 12:31:53 +01:00
a993c4e0d4 adding linux ci and fixing problems 2023-01-16 12:31:53 +01:00
fe9cc20d00 make get const 2023-01-16 12:31:53 +01:00
552a12a6ad updates for source sequence counter 2023-01-16 12:31:47 +01:00
13639feec6 FreeRTOS unittests building (but not running) 2023-01-16 12:30:36 +01:00
654de0f586 WIP 2023-01-16 12:30:36 +01:00
0e7c6b117f Merge pull request 'Service 11 TC Scheduler Robustness Improvements' (#720) from service_11_bugfixes into development
Reviewed-on: fsfw/fsfw#720
2023-01-13 13:33:19 +01:00
d16c5024dc small include improvement 2023-01-13 11:15:36 +01:00
a4531e4ced typo 2023-01-13 10:59:39 +01:00
97c629ad84 update changelog 2023-01-13 10:53:36 +01:00
bf12f284fa add size and crc check for contained TC 2023-01-13 10:53:04 +01:00
8589f4d63a Merge pull request 'updates for source sequence counter' (#714) from eive/fsfw:source_seq_counter_update into development
Reviewed-on: fsfw/fsfw#714
2022-12-19 15:00:28 +01:00
ca80589233 make get const 2022-12-19 14:58:08 +01:00
f2ebaed092 Merge pull request 'vec getter, reset for content' (#716) from eive/fsfw:get_cmd_exec_read_buf into development
Reviewed-on: fsfw/fsfw#716
2022-12-19 14:56:11 +01:00
f0b89e98df Merge pull request 'printout handling improvements' (#717) from eive/fsfw:i2c_printout_improvements into development
Reviewed-on: fsfw/fsfw#717
2022-12-19 14:45:04 +01:00
5557d95994 Merge branch 'development' into i2c_printout_improvements 2022-12-05 14:20:58 +01:00
fc24c9b5d8 Merge branch 'development' into get_cmd_exec_read_buf 2022-12-05 14:20:52 +01:00
7ef69c839c Merge pull request 'small fix to allow teardown handling' (#713) from eive/fsfw:mueller/shutdown_for_failed_to_on_transition into development
Reviewed-on: fsfw/fsfw#713
2022-11-28 14:30:15 +01:00
9b798d798e Merge pull request 'DLE parser' (#711) from eive/fsfw:mueller/dle_parser into development
Reviewed-on: fsfw/fsfw#711
2022-11-28 14:13:18 +01:00
b13453f46b vec getter, reset for content 2022-11-28 08:43:54 +01:00
d0e322d7e2 printout handling improvements 2022-11-28 08:42:08 +01:00
ecde164f68 updates for source sequence counter 2022-11-28 08:30:45 +01:00
50930b41ba Merge remote-tracking branch 'upstream/development' into mueller/dle_parser 2022-11-28 08:27:24 +01:00
d6ee2ed400 Merge pull request 'AcceptsTelemetryIF tweaks' (#712) from eive/fsfw:mueller/accepts_tm_if_adaptions into development
Reviewed-on: fsfw/fsfw#712
2022-11-21 16:30:43 +01:00
f2150ff9c2 Merge pull request 'only delete table entry if not nullptr' (#710) from eive/fsfw:mueller/health_helper_bugfix into development
Reviewed-on: fsfw/fsfw#710
2022-11-21 16:24:13 +01:00
1b9c98f3fe Merge pull request 'uio able to resolve symlinks now' (#709) from eive/fsfw:mueller/uio_mapper_handle_symlinks into development
Reviewed-on: fsfw/fsfw#709
2022-11-21 16:14:36 +01:00
742152b28e Merge branch 'development' into mueller/accepts_tm_if_adaptions 2022-11-21 15:29:35 +01:00
bf4ca56658 Merge branch 'development' into mueller/shutdown_for_failed_to_on_transition 2022-11-21 15:29:11 +01:00
16ffa00155 Merge branch 'development' into mueller/dle_parser 2022-11-21 15:28:34 +01:00
14c681c93a Merge branch 'development' into mueller/uio_mapper_handle_symlinks 2022-11-21 15:27:06 +01:00
0958c3a00e Merge branch 'development' into mueller/health_helper_bugfix 2022-11-21 15:24:51 +01:00
d699d16307 Merge pull request 'SP reader getPacketData is const now' (#708) from eive/fsfw:mueller/sp_reader_const_get_data into development
Reviewed-on: fsfw/fsfw#708
2022-11-21 15:23:39 +01:00
3b0fed733f Merge branch 'development' into mueller/uio_mapper_handle_symlinks 2022-11-21 15:23:15 +01:00
23d3812fe3 this is actually important 2022-11-21 15:22:25 +01:00
dec7db3ae2 Merge remote-tracking branch 'upstream/development' into mueller/accepts_tm_if_adaptions 2022-11-21 15:00:06 +01:00
65a5abab49 move free call 2022-11-21 14:56:08 +01:00
0129783e34 Merge branch 'development' into mueller/sp_reader_const_get_data 2022-11-21 14:50:44 +01:00
cabe0868ec Merge pull request 'move container returnvalues to namespace' (#707) from eive/fsfw:mueller/update_containers_retval into development
Reviewed-on: fsfw/fsfw#707
2022-11-21 14:49:44 +01:00
f05295bada small fix to allow teardown handling 2022-11-17 15:16:29 +01:00
b85ca64690 update changelog 2022-11-15 11:48:28 +01:00
3bc3da5a8d update changelog 2022-11-15 11:47:26 +01:00
f8c07ec9cf update changelog 2022-11-15 11:46:43 +01:00
8199b8f359 bump changelog 2022-11-15 11:45:39 +01:00
cbc8dbcdd4 update changelog 2022-11-15 11:44:45 +01:00
d31a5306f0 fix mock 2022-11-15 11:41:03 +01:00
a236a5ec50 adaptions for AcceptsTelemetryIF 2022-11-15 11:40:26 +01:00
03620970e2 function to get queue is const now 2022-11-15 11:38:32 +01:00
8fe8d810e9 only delete table if not nullptr 2022-11-15 11:27:31 +01:00
9483c2809d DLE parser 2022-11-15 11:26:53 +01:00
fe3d6bd432 uio able to resolve symlinks now 2022-11-15 10:56:46 +01:00
2a842666d5 SP reader getPacketData is const now 2022-11-15 10:46:46 +01:00
c013fcc1f5 move container retvals to namespace 2022-11-15 10:01:37 +01:00
1b8fc2af19 Merge pull request 'CFDP Update' (#682) from mueller/cfdp-update-without-handlers into development
Reviewed-on: fsfw/fsfw#682
2022-11-14 15:04:43 +01:00
72d7c43445 updates for storage manager mock 2022-11-14 14:57:37 +01:00
ab9b6c8c89 Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-11-14 14:51:33 +01:00
69d338f9bb Merge pull request 'Local Pool Update Remove Add Data Ignore Fault Argument' (#701) from eive/fsfw:mueller/local-pool-update-remove-ignore-fault-arg into development
Reviewed-on: fsfw/fsfw#701
2022-11-14 14:49:34 +01:00
68223869d5 Merge branch 'development' into mueller/local-pool-update-remove-ignore-fault-arg 2022-11-14 14:47:07 +01:00
93fda71989 Merge pull request 'refactoring of serial drivers for linux' (#705) from eive/fsfw:mueller/refactor_serial_linux into development
Reviewed-on: fsfw/fsfw#705
2022-11-14 14:39:41 +01:00
7b0db08962 Merge branch 'development' into mueller/refactor_serial_linux 2022-11-14 14:36:31 +01:00
0956fbc740 Merge pull request 'fix compiler warning for fixed array list copy ctor' (#704) from eive/fsfw:mueller/fixed_array_list_copy_ctor into development
Reviewed-on: fsfw/fsfw#704
2022-11-14 14:28:46 +01:00
b48e0fdc0d Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-11-14 14:25:36 +01:00
1d084ee22f Merge branch 'development' into mueller/fixed_array_list_copy_ctor 2022-11-14 14:21:04 +01:00
1bea2344f6 remove using declaraction 2022-11-14 14:21:00 +01:00
d7e16a67a7 Merge pull request 'Windows Tweaks' (#691) from eive/fsfw:windows-tweaks-upstream into development
Reviewed-on: fsfw/fsfw#691
2022-11-14 14:18:47 +01:00
6021d897b8 Merge branch 'development' into windows-tweaks-upstream 2022-11-14 14:13:57 +01:00
83a6f0b5f8 reenable setup function call 2022-11-14 14:12:26 +01:00
a9c6c088f2 remove leftover debugging code 2022-11-14 14:08:38 +01:00
b6a3c206cc smaller include tweaks 2022-11-11 11:34:58 +01:00
5b352978c5 rename cookie class 2022-11-11 11:33:35 +01:00
819a298b19 refactoring of serial drivers for linux 2022-11-10 17:50:21 +01:00
16246d6ece replace other memcpy 2022-11-10 16:18:36 +01:00
5c84f12440 this not crash 2022-11-10 16:15:52 +01:00
83c2c4825c fix compiler error for fixed array list copy ctor 2022-11-10 15:54:03 +01:00
c913fe40bf tweaks 2022-11-09 17:54:08 +01:00
70ec08bf1d Merge pull request 'missing include' (#703) from KSat/fsfw:mueller/time_reader_include into development
Reviewed-on: fsfw/fsfw#703
2022-11-09 16:59:25 +01:00
ef23665d9c Merge branch 'development' into mueller/time_reader_include 2022-11-09 16:39:55 +01:00
eefc122292 Merge pull request 'defaultconfig did not build anymore' (#702) from mohr/fix_defaultconfig into development
Reviewed-on: fsfw/fsfw#702
2022-11-09 14:12:41 +01:00
bee33526a1 missing include 2022-11-09 13:49:40 +01:00
f715b65d6e Merge remote-tracking branch 'upstream/development' into mueller/local-pool-update-remove-ignore-fault-arg 2022-10-28 10:06:04 +02:00
c11af63015 Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-10-28 10:04:21 +02:00
dc1583c932 Merge branch 'development' into windows-tweaks-upstream 2022-10-24 17:10:44 +02:00
81a7de2814 make dtor virtual 2022-10-24 16:39:32 +02:00
d26f230bee builds 2022-10-24 15:43:20 +02:00
4db124c680 ignore fault 2022-10-24 15:41:29 +02:00
2df66c9304 Merge branch 'mueller/local-pool-update' of https://egit.irs.uni-stuttgart.de/fsfw/fsfw into mueller/local-pool-update 2022-10-24 14:39:11 +02:00
54ad6b3016 add some docs 2022-10-24 14:39:05 +02:00
73e313c35b Merge branch 'development' into mueller/local-pool-update 2022-10-24 14:35:24 +02:00
dd2f42d22b Merge branch 'development' into mueller/local-pool-update 2022-10-24 14:34:56 +02:00
652c31a683 missing validity check 2022-10-17 17:25:27 +02:00
bfe120636c this should have the same effect 2022-10-17 15:08:46 +02:00
a8041f220f Merge branch 'development' into mueller/cfdp-update-without-handlers 2022-10-17 14:44:28 +02:00
dd636b186b size check bugfix 2022-10-17 14:30:27 +02:00
3349fc36f8 Merge branch 'development' into windows-tweaks-upstream 2022-10-17 14:20:48 +02:00
df06064df0 Merge branch 'development' into windows-tweaks-upstream 2022-10-10 13:41:09 +02:00
e0c780f21c better comment 2022-09-28 09:59:31 +02:00
876815b1c9 another small windows tweak 2022-09-28 09:59:22 +02:00
b0ecf87580 last windows tweak 2022-09-28 09:59:12 +02:00
68ce8b5b08 tweaks to make windows build again 2022-09-28 09:59:02 +02:00
fe03da6def Merge remote-tracking branch 'origin/development' into mueller/cfdp-update-without-handlers 2022-09-26 15:38:45 +02:00
4f7f8310c9 Merge remote-tracking branch 'origin/development' into mueller/local-pool-update 2022-09-15 11:00:43 +02:00
159 changed files with 1619 additions and 3149 deletions

View File

@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Fixes
- TC Scheduler Service 11: Add size and CRC check for contained TC.
- Only delete health table entry in `HealthHelper` destructor if
health table was set.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -24,19 +28,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Added
- DHB TM handler `handleDeviceTM` renamed to `handleDeviceTm` and now takes
`util::DataWrapper` as the data input argument. This allows more flexibility in the possible
types of telemetry.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/669
- Add `util::DataWrapper` class inside the `util` module. This is a tagged union which allows
to specify raw data either as a classic C-style raw pointer and size or as a `SerializeIF`
pointer.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/668
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
- `UioMapper` is able to resolve symlinks now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
## Changes
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- Moved some container returnvalues to dedicated header and namespace
to they can be used without template specification.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
- Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
`uint16_t getTmSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)`
@ -65,6 +70,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
- Make functions `const` where it makes sense
- Add `const char* getName const` abstract function
@ -225,6 +234,7 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
Easiest solution for now: Keep this option OFF by default.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
inside `fsfw/version.h`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
@ -239,17 +249,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
- `Subsystem`: New API to add table and sequence entries
## HAL
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
lot more sense because each ComIF should be responsible for one SPI bus.
- SPI: Move the empty transfer to update the line polarity to separate function. This means
it is not automatically called when calling the setter function for SPI speed and mode.
The user should call this function after locking the CS mutex if multiple SPI devices with
differing speeds and modes are attached to one bus.
- SPI: Getter functions for SPI speed and mode.
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
## Fixed
- TCP TMTC Server: `MutexGuard` was not created properly in

View File

@ -122,6 +122,7 @@ if(UNIX)
option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add Linux peripheral drivers"
OFF)
option(FSFW_HAL_LINUX_ADD_LIBGPIOD "Attempt to add Linux GPIOD drivers" OFF)
option(FSFW_HAL_LINUX_ADD_SERIAL_DRIVERS "Add serial drivers" ON)
endif()
# Optional sources
@ -152,7 +153,7 @@ if(FSFW_BUILD_TESTS)
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
)
# Check whether the user has already installed Catch2 first
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION})
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide Catch2
if(NOT Catch2_FOUND)
message(
@ -173,6 +174,27 @@ if(FSFW_BUILD_TESTS)
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.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)
add_executable(${FSFW_TEST_TGT})
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
@ -195,7 +217,7 @@ message(
)
# Check whether the user has already installed ETL first
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide etl
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message(
@ -225,6 +247,7 @@ if(FSFW_FETCH_CONTENT_TARGETS)
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif()
endif()
set(FSFW_CORE_INC_PATH "inc")
@ -359,6 +382,9 @@ if(FSFW_BUILD_TESTS)
endif()
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
${LIB_FSFW_NAME})
if(FSFW_OSAL MATCHES "freertos")
target_link_libraries(${FSFW_TEST_TGT} PRIVATE FreeRTOS)
endif()
endif()
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If

View File

@ -5,7 +5,7 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync
RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync wget qemu-system-arm
RUN python3 -m pip install sphinx breathe
@ -21,8 +21,12 @@ RUN git clone https://github.com/ETLCPP/etl.git && \
cmake -B build . && \
cmake --install 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"
#ssh needs a valid user to work
RUN adduser --uid 114 jenkins
RUN adduser -q --uid 114 jenkins
#add documentation server to known hosts
RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts

View File

@ -1,48 +1,65 @@
pipeline {
environment {
BUILDDIR = 'cmake-build-tests'
BUILDDIR_HOST = 'cmake-build-tests-host'
BUILDDIR_LINUX = 'cmake-build-tests-linux'
BUILDDIR_FREERTOS = 'cmake-build-tests-freertos'
BUILDDIR_RTEMS = 'cmake-build-tests-rtems'
DOCDDIR = 'cmake-build-documentation'
}
agent {
docker {
image 'fsfw-ci:d6'
args '--network host'
image 'fsfw-ci:d7'
args '--network host --sysctl fs.mqueue.msg_max=100'
}
}
stages {
stage('Clean') {
stage('Host') {
steps {
sh 'rm -rf $BUILDDIR'
}
}
stage('Configure') {
steps {
dir(BUILDDIR) {
sh 'rm -rf $BUILDDIR_HOST'
dir(BUILDDIR_HOST) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}
stage('Build') {
steps {
dir(BUILDDIR) {
sh 'cmake --build . -j4'
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
}
stage('Valgrind') {
stage('Linux') {
steps {
dir(BUILDDIR) {
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('FreeRTOS') {
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('rtems') {
steps {
sh 'rm -rf $BUILDDIR_RTEMS'
dir(BUILDDIR_RTEMS) {
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 ..'
sh 'cmake --build . -j4'
sh 'qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio -semihosting -machine virt,gic-version=3 -cpu cortex-a72 -m 4000 -kernel fsfw-tests'
}
}
}
stage('Documentation') {
when {
branch 'development'

View File

@ -140,7 +140,7 @@ find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( GCOVR_PATH gcovr )
find_program( CPPFILT_PATH NAMES c++filt )
if(NOT GCOV_PATH)

View File

@ -16,8 +16,8 @@ class CommandActionHelper {
public:
explicit CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper();
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
const uint8_t* data = nullptr, uint32_t size = 0);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
uint32_t size);
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply);

View File

@ -2,10 +2,7 @@
#define FSFW_CFDP_H
#include "cfdp/definitions.h"
#include "cfdp/handler/CfdpHandler.h"
#include "cfdp/handler/DestHandler.h"
#include "cfdp/handler/FaultHandlerBase.h"
#include "cfdp/helpers.h"
#include "cfdp/tlv/Lv.h"
#include "cfdp/tlv/StringLv.h"
#include "cfdp/tlv/Tlv.h"

View File

@ -1,3 +1 @@
target_sources(
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)

View File

@ -1,134 +0,0 @@
#include "CfdpHandler.h"
#include "fsfw/cfdp/pdu/AckPduReader.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
using namespace cfdp;
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
: SystemObject(fsfwParams.objectId),
msgQueue(fsfwParams.msgQueue),
destHandler(
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
cfdpCfg.lostSegmentsList),
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
fsfwParams.tmStore)) {
destHandler.setMsgQueue(msgQueue);
}
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
return destHandler.getDestHandlerParams().cfg.localId.getValue();
}
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
ReturnValue_t CfdpHandler::initialize() {
ReturnValue_t result = destHandler.initialize();
if (result != OK) {
return result;
}
tcStore = destHandler.getTcStore();
tmStore = destHandler.getTmStore();
return SystemObject::initialize();
}
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
// correct or more appropriate
ReturnValue_t status;
ReturnValue_t result = OK;
TmTcMessage tmtcMsg;
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
status = msgQueue.receiveMessage(&tmtcMsg)) {
result = handleCfdpPacket(tmtcMsg);
if (result != OK) {
status = result;
}
}
auto& fsmRes = destHandler.performStateMachine();
// TODO: Error handling?
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
destHandler.performStateMachine();
// TODO: Error handling?
}
return status;
}
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
auto accessorPair = tcStore->getData(msg.getStorageId());
if (accessorPair.first != OK) {
return accessorPair.first;
}
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
ReturnValue_t result = reader.parseData();
if (result != returnvalue::OK) {
return INVALID_PDU_FORMAT;
}
// The CFDP distributor should have taken care of ensuring the destination ID is correct
PduType type = reader.getPduType();
// Only the destination handler can process these PDUs
if (type == PduType::FILE_DATA) {
// Disable auto-deletion of packet
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId());
result = destHandler.passPacket(info);
} else {
// Route depending on PDU type and directive type if applicable. It retrieves directive type
// from the raw stream for better performance (with sanity and directive code check).
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
// procedure.
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
// with at least one byte being the directive code
const uint8_t* pduDataField = reader.getPduDataField();
if (pduDataField == nullptr) {
return INVALID_PDU_FORMAT;
}
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
return INVALID_DIRECTIVE_FIELD;
}
auto directive = static_cast<FileDirective>(pduDataField[0]);
auto passToDestHandler = [&]() {
accessorPair.second.release();
PacketInfo info(type, msg.getStorageId(), directive);
result = destHandler.passPacket(info);
};
auto passToSourceHandler = [&]() {
};
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
directive == FileDirective::PROMPT) {
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
// the destination handler
passToDestHandler();
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
directive == FileDirective::KEEP_ALIVE) {
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
// the source handler
passToSourceHandler();
} else if (directive == FileDirective::ACK) {
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
// the source handler, for a Finished PDU, it is passed to the destination handler.
FileDirective ackedDirective;
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
return INVALID_ACK_DIRECTIVE_FIELDS;
}
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
passToSourceHandler();
} else if (ackedDirective == FileDirective::FINISH) {
passToDestHandler();
}
}
}
return result;
}

View File

@ -1,71 +0,0 @@
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
#include <utility>
#include "fsfw/cfdp/handler/DestHandler.h"
#include "fsfw/objectmanager/SystemObject.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
struct FsfwHandlerParams {
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
: objectId(objectId),
vfs(vfs),
packetDest(packetDest),
tcStore(tcStore),
tmStore(tmStore),
msgQueue(msgQueue) {}
object_id_t objectId{};
HasFileSystemIF& vfs;
AcceptsTelemetryIF& packetDest;
StorageManagerIF& tcStore;
StorageManagerIF& tmStore;
MessageQueueIF& msgQueue;
};
struct CfdpHandlerCfg {
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
cfdp::RemoteConfigTableIF& remoteCfgProvider)
: id(std::move(localId)),
indicCfg(indicationCfg),
packetInfoList(packetInfo),
lostSegmentsList(lostSegmentsList),
remoteCfgProvider(remoteCfgProvider),
userHandler(userHandler),
faultHandler(userFaultHandler) {}
cfdp::EntityId id;
cfdp::IndicationCfg indicCfg;
cfdp::PacketInfoListBase& packetInfoList;
cfdp::LostSegmentsListBase& lostSegmentsList;
cfdp::RemoteConfigTableIF& remoteCfgProvider;
cfdp::UserBase& userHandler;
cfdp::FaultHandlerBase& faultHandler;
};
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
public:
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
[[nodiscard]] const char* getName() const override;
[[nodiscard]] uint32_t getIdentifier() const override;
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
ReturnValue_t initialize() override;
ReturnValue_t performOperation(uint8_t operationCode) override;
private:
MessageQueueIF& msgQueue;
cfdp::DestHandler destHandler;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
};
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H

View File

@ -1,490 +0,0 @@
#include "DestHandler.h"
#include <etl/crc32.h>
#include <utility>
#include "fsfw/FSFW.h"
#include "fsfw/cfdp/pdu/EofPduReader.h"
#include "fsfw/cfdp/pdu/FileDataReader.h"
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
#include "fsfw/objectmanager.h"
#include "fsfw/tmtcservices/TmTcMessage.h"
using namespace returnvalue;
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
: tlvVec(params.maxTlvsInOnePdu),
userTlvVec(params.maxTlvsInOnePdu),
dp(std::move(params)),
fp(fsfwParams),
tp(params.maxFilenameLen) {
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
ReturnValue_t result;
uint8_t errorIdx = 0;
fsmRes.resetOfIteration();
if (fsmRes.step == TransactionStep::IDLE) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::METADATA) {
result = handleMetadataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
}
if (fsmRes.step == TransactionStep::IDLE) {
// To decrease the already high complexity of the software, all packets arriving before
// a metadata PDU are deleted.
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
fp.tcStore->deleteData(infoIter->storeId);
infoIter++;
}
dp.packetListRef.clear();
}
if (fsmRes.step != TransactionStep::IDLE) {
fsmRes.callStatus = CallStatus::CALL_AGAIN;
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
if (infoIter->pduType == PduType::FILE_DATA) {
result = handleFileDataPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
// TODO: Support for check timer missing
result = handleEofPdu(*infoIter);
checkAndHandleError(result, errorIdx);
// Store data was deleted in PDU handler because a store guard is used
dp.packetListRef.erase(infoIter++);
} else {
infoIter++;
}
}
}
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
result = handleTransferCompletion();
checkAndHandleError(result, errorIdx);
}
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
result = sendFinishedPdu();
checkAndHandleError(result, errorIdx);
finish();
}
return updateFsmRes(errorIdx);
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
// TODO: Will be implemented at a later stage
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
#endif
}
return updateFsmRes(errorIdx);
}
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
if (dp.packetListRef.full()) {
return FAILED;
}
dp.packetListRef.push_back(packet);
return OK;
}
ReturnValue_t cfdp::DestHandler::initialize() {
if (fp.tmStore == nullptr) {
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
if (fp.tmStore == nullptr) {
return FAILED;
}
}
if (fp.tcStore == nullptr) {
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
if (fp.tcStore == nullptr) {
return FAILED;
}
}
if (fp.msgQueue == nullptr) {
return FAILED;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
// Process metadata PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::StringLv sourceFileName;
cfdp::StringLv destFileName;
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
metadataInfo);
ReturnValue_t result = reader.parseData();
// TODO: The standard does not really specify what happens if this kind of error happens
// I think it might be a good idea to cache some sort of error code, which
// is translated into a warning and/or event by an upper layer
if (result != OK) {
return handleMetadataParseError(result, constAccessorPair.second.data(),
constAccessorPair.second.size());
}
return startTransaction(reader, metadataInfo);
}
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
// Process file data PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
cfdp::FileSize offset;
FileDataInfo fdInfo(offset);
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
ReturnValue_t result = reader.parseData();
if (result != OK) {
return result;
}
size_t fileSegmentLen = 0;
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
fileOpParams.offset = offset.value();
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
FileSegmentRecvdParams segParams;
segParams.offset = offset.value();
segParams.id = tp.transactionId;
segParams.length = fileSegmentLen;
segParams.recContState = fdInfo.getRecordContinuationState();
size_t segmentMetadatLen = 0;
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
dp.user.fileSegmentRecvdIndication(segParams);
}
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
if (offset.value() + fileSegmentLen > tp.progress) {
tp.progress = offset.value() + fileSegmentLen;
}
if (result != returnvalue::OK) {
// TODO: Proper Error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "File write error" << std::endl;
#endif
} else {
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
}
return result;
}
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
// Process EOF PDU
auto constAccessorPair = fp.tcStore->getData(info.storeId);
if (constAccessorPair.first != OK) {
// TODO: This is not a CFDP error. Event and/or warning?
return constAccessorPair.first;
}
EofInfo eofInfo(nullptr);
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
ReturnValue_t result = reader.parseData();
if (result != OK) {
return result;
}
// TODO: Error handling
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
tp.crc = eofInfo.getChecksum();
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
if (fileSizeFromEof > tp.progress) {
// TODO: File size error
}
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
}
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
dp.user.eofRecvIndication(getTransactionId());
}
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
}
}
return returnvalue::OK;
}
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
const uint8_t* rawData, size_t maxSize) {
// TODO: try to extract destination ID for error
// TODO: Invalid metadata PDU.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
#else
#endif
PduHeaderReader headerReader(rawData, maxSize);
result = headerReader.parseData();
if (result != OK) {
// TODO: Now this really should not happen. Warning or error,
// yield or cache appropriate returnvalue
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Parsing Header failed" << std::endl;
#else
#endif
// TODO: Trigger appropriate event
return result;
}
cfdp::EntityId destId;
headerReader.getDestId(destId);
RemoteEntityCfg* remoteCfg;
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
// covered by the standard.
// Warning or error, yield or cache appropriate returnvalue
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "No remote config exists for destination ID" << std::endl;
#else
#endif
// TODO: Trigger appropriate event
}
// TODO: Appropriate returnvalue?
return returnvalue::FAILED;
}
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
if (fsmRes.state != CfdpStates::IDLE) {
// According to standard, discard metadata PDU if we are busy
return OK;
}
ReturnValue_t result = OK;
fsmRes.step = TransactionStep::TRANSACTION_START;
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
}
tp.checksumType = info.getChecksumType();
tp.closureRequested = info.isClosureRequested();
size_t sourceNameSize = 0;
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
if (sourceNameSize > tp.sourceName.size()) {
// TODO: Warning, event etc.
return FAILED;
}
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
tp.sourceName[sourceNameSize] = '\0';
size_t destNameSize = 0;
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
if (destNameSize > tp.destName.size()) {
// TODO: Warning, event etc.
return FAILED;
}
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
tp.destName[destNameSize] = '\0';
reader.fillConfig(tp.pduConf);
tp.pduConf.direction = Direction::TOWARDS_SENDER;
tp.transactionId.entityId = tp.pduConf.sourceId;
tp.transactionId.seqNum = tp.pduConf.seqNum;
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
// TODO: Warning, event etc.
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler" << __func__
<< ": No remote configuration found for destination ID "
<< tp.pduConf.sourceId.getValue() << std::endl;
#endif
return FAILED;
}
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
// so there is no need to create a file or truncate an existing file
if (destNameSize > 0 and sourceNameSize > 0) {
FilesystemParams fparams(tp.destName.data());
// TODO: Filesystem errors?
if (dp.user.vfs.fileExists(fparams)) {
dp.user.vfs.truncateFile(fparams);
} else {
result = dp.user.vfs.createFile(fparams);
if (result != OK) {
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
// CFDP.
// In any case, it does not really make sense to continue here
}
}
}
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
params.fileSize = tp.fileSize.getSize();
params.destFileName = tp.destName.data();
params.sourceFileName = tp.sourceName.data();
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
params.msgsToUserLen = info.getOptionsLen();
dp.user.metadataRecvdIndication(params);
return result;
}
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
ReturnValue_t result;
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
result = checksumVerification();
if (result != OK) {
// TODO: Warning / error handling?
}
} else {
tp.conditionCode = ConditionCode::NO_ERROR;
}
result = noticeOfCompletion();
if (result != OK) {
}
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
if (tp.closureRequested) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
} else {
finish();
}
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
}
return OK;
}
void cfdp::DestHandler::finish() {
tp.reset();
dp.packetListRef.clear();
fsmRes.state = CfdpStates::IDLE;
fsmRes.step = TransactionStep::IDLE;
}
ReturnValue_t cfdp::DestHandler::checksumVerification() {
std::array<uint8_t, 1024> buf{};
// TODO: Checksum verification and notice of completion
etl::crc32 crcCalc;
uint64_t currentOffset = 0;
FileOpParams params(tp.destName.data(), tp.fileSize.value());
while (currentOffset < tp.fileSize.value()) {
uint64_t readLen;
if (currentOffset + buf.size() > tp.fileSize.value()) {
readLen = tp.fileSize.value() - currentOffset;
} else {
readLen = buf.size();
}
if (readLen > 0) {
params.offset = currentOffset;
params.size = readLen;
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
if (result != OK) {
// TODO: I think this is a case for a filestore rejection, but it might sense to print
// a warning or trigger an event because this should generally not happen
return FAILED;
}
crcCalc.add(buf.begin(), buf.begin() + readLen);
}
currentOffset += readLen;
}
uint32_t value = crcCalc.value();
if (value == tp.crc) {
tp.conditionCode = ConditionCode::NO_ERROR;
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
} else {
// TODO: Proper error handling
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
#endif
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
}
return OK;
}
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
tp.deliveryStatus);
dp.user.transactionFinishedIndication(params);
}
return OK;
}
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
FinishPduCreator finishedPdu(tp.pduConf, info);
store_address_t storeId;
uint8_t* dataPtr = nullptr;
ReturnValue_t result =
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
return result;
}
size_t serLen = 0;
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
<< std::endl;
#endif
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
return result;
}
TmTcMessage msg(storeId);
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
if (result != OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
#endif
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
return result;
}
fsmRes.packetsSent++;
return OK;
}
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
return fsmRes.step;
}
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
fsmRes.errors = errors;
fsmRes.result = OK;
if (fsmRes.errors > 0) {
fsmRes.result = FAILED;
}
return fsmRes;
}
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
if (result != OK and errorIdx < 3) {
fsmRes.errorCodes[errorIdx] = result;
errorIdx++;
}
}
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
fp.eventReporter = &reporter;
}
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }

View File

@ -1,202 +0,0 @@
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
#define FSFW_CFDP_CFDPDESTHANDLER_H
#include <etl/list.h>
#include <etl/set.h>
#include <optional>
#include <utility>
#include "RemoteConfigTableIF.h"
#include "UserBase.h"
#include "defs.h"
#include "fsfw/cfdp/handler/mib.h"
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/storagemanager/StorageManagerIF.h"
#include "fsfw/storagemanager/storeAddress.h"
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
namespace cfdp {
struct PacketInfo {
PacketInfo(PduType type, store_address_t storeId,
std::optional<FileDirective> directive = std::nullopt)
: pduType(type), directiveType(directive), storeId(storeId) {}
PduType pduType = PduType::FILE_DATA;
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
store_address_t storeId = store_address_t::invalid();
PacketInfo() = default;
};
template <size_t SIZE>
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
template <size_t SIZE>
using PacketInfoList = etl::list<PacketInfo, SIZE>;
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
using PacketInfoListBase = etl::ilist<PacketInfo>;
struct DestHandlerParams {
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
PacketInfoListBase& packetList,
// TODO: This container can potentially take tons of space. For a better
// memory efficient implementation, an additional abstraction could be
// be used so users can use uint32_t as the pair type
LostSegmentsListBase& lostSegmentsContainer)
: cfg(std::move(cfg)),
user(user),
remoteCfgTable(remoteCfgTable),
packetListRef(packetList),
lostSegmentsContainer(lostSegmentsContainer) {}
LocalEntityCfg cfg;
UserBase& user;
RemoteConfigTableIF& remoteCfgTable;
PacketInfoListBase& packetListRef;
LostSegmentsListBase& lostSegmentsContainer;
uint8_t maxTlvsInOnePdu = 10;
size_t maxFilenameLen = 255;
};
struct FsfwParams {
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
StorageManagerIF& tmStore)
: FsfwParams(packetDest, msgQueue, eventReporter) {
this->tcStore = &tcStore;
this->tmStore = &tmStore;
}
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
EventReportingProxyIF* eventReporter)
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
AcceptsTelemetryIF& packetDest;
MessageQueueIF* msgQueue;
EventReportingProxyIF* eventReporter = nullptr;
StorageManagerIF* tcStore = nullptr;
StorageManagerIF* tmStore = nullptr;
};
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
class DestHandler {
public:
enum class TransactionStep {
IDLE = 0,
TRANSACTION_START = 1,
RECEIVING_FILE_DATA_PDUS = 2,
SENDING_ACK_PDU = 3,
TRANSFER_COMPLETION = 4,
SENDING_FINISHED_PDU = 5
};
struct FsmResult {
public:
ReturnValue_t result = returnvalue::OK;
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
TransactionStep step = TransactionStep::IDLE;
CfdpStates state = CfdpStates::IDLE;
uint32_t packetsSent = 0;
uint8_t errors = 0;
std::array<ReturnValue_t, 3> errorCodes = {};
void resetOfIteration() {
result = returnvalue::OK;
callStatus = CallStatus::CALL_AFTER_DELAY;
packetsSent = 0;
errors = 0;
errorCodes.fill(returnvalue::OK);
}
};
/**
* Will be returned if it is advisable to call the state machine operation call again
*/
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
/**
*
* @return
* - @c returnvalue::OK State machine OK for this execution cycle
* - @c CALL_FSM_AGAIN State machine should be called again.
*/
const FsmResult& performStateMachine();
void setMsgQueue(MessageQueueIF& queue);
void setEventReporter(EventReportingProxyIF& reporter);
ReturnValue_t passPacket(PacketInfo packet);
ReturnValue_t initialize();
[[nodiscard]] CfdpStates getCfdpState() const;
[[nodiscard]] TransactionStep getTransactionStep() const;
[[nodiscard]] const TransactionId& getTransactionId() const;
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
[[nodiscard]] StorageManagerIF* getTcStore() const;
[[nodiscard]] StorageManagerIF* getTmStore() const;
private:
struct TransactionParams {
// Initialize char vectors with length + 1 for 0 termination
explicit TransactionParams(size_t maxFileNameLen)
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
void reset() {
pduConf = PduConfig();
transactionId = TransactionId();
std::fill(sourceName.begin(), sourceName.end(), '\0');
std::fill(destName.begin(), destName.end(), '\0');
fileSize.setFileSize(0, false);
conditionCode = ConditionCode::NO_ERROR;
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
crc = 0;
progress = 0;
remoteCfg = nullptr;
closureRequested = false;
checksumType = ChecksumType::NULL_CHECKSUM;
}
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
bool closureRequested = false;
std::vector<char> sourceName;
std::vector<char> destName;
cfdp::FileSize fileSize;
TransactionId transactionId;
PduConfig pduConf;
ConditionCode conditionCode = ConditionCode::NO_ERROR;
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
uint32_t crc = 0;
uint64_t progress = 0;
RemoteEntityCfg* remoteCfg = nullptr;
};
std::vector<cfdp::Tlv> tlvVec;
std::vector<cfdp::Tlv> userTlvVec;
DestHandlerParams dp;
FsfwParams fp;
TransactionParams tp;
FsmResult fsmRes;
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
ReturnValue_t handleEofPdu(const PacketInfo& info);
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
size_t maxSize);
ReturnValue_t handleTransferCompletion();
ReturnValue_t sendFinishedPdu();
ReturnValue_t noticeOfCompletion();
ReturnValue_t checksumVerification();
const FsmResult& updateFsmRes(uint8_t errors);
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
void finish();
};
} // namespace cfdp
#endif // FSFW_CFDP_CFDPDESTHANDLER_H

View File

@ -1 +0,0 @@
#include "SourceHandler.h"

View File

@ -1,6 +0,0 @@
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
class SourceHandler {};
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H

View File

@ -5,15 +5,5 @@ namespace cfdp {
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
namespace events {
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
} // namespace events
} // namespace cfdp
}
#endif // FSFW_CFDP_HANDLER_DEFS_H

View File

@ -4,6 +4,7 @@
#include "../returnvalues/returnvalue.h"
#include "../serialize/SerializeAdapter.h"
#include "../serialize/SerializeIF.h"
#include "definitions.h"
/**
* @brief A List that stores its values in an array.
@ -19,9 +20,6 @@ class ArrayList {
friend class SerialArrayListAdapter;
public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/**
* This is the allocating constructor.
* It allocates an array of the specified size.
@ -187,7 +185,7 @@ class ArrayList {
*/
ReturnValue_t insert(T entry) {
if (size >= maxSize_) {
return FULL;
return containers::LIST_FULL;
}
entries[size] = entry;
++size;

View File

@ -20,15 +20,19 @@ class FixedArrayList : public ArrayList<T, count_t> {
FixedArrayList() : ArrayList<T, count_t>(data, MAX_SIZE) {}
FixedArrayList(const FixedArrayList& other) : ArrayList<T, count_t>(data, MAX_SIZE) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
for (size_t idx = 0; idx < this->size; idx++) {
data[idx] = other.data[idx];
}
}
FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data));
this->entries = data;
this->size = other.size;
for (size_t idx = 0; idx < this->size; idx++) {
data[idx] = other.data[idx];
}
return *this;
}

View File

@ -4,8 +4,8 @@
#include <type_traits>
#include <utility>
#include "../returnvalues/returnvalue.h"
#include "ArrayList.h"
#include "definitions.h"
/**
* @brief Map implementation for maps with a pre-defined size.
@ -24,11 +24,6 @@ class FixedMap : public SerializeIF {
"derived class from SerializeIF to be serialize-able");
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
private:
static const key_t EMPTY_SLOT = -1;
ArrayList<std::pair<key_t, T>, uint32_t> theMap;
@ -76,10 +71,10 @@ class FixedMap : public SerializeIF {
ReturnValue_t insert(key_t key, T value, Iterator* storedValue = nullptr) {
if (exists(key) == returnvalue::OK) {
return KEY_ALREADY_EXISTS;
return containers::KEY_ALREADY_EXISTS;
}
if (_size == theMap.maxSize()) {
return MAP_FULL;
return containers::MAP_FULL;
}
theMap[_size].first = key;
theMap[_size].second = value;
@ -93,7 +88,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t insert(std::pair<key_t, T> pair) { return insert(pair.first, pair.second); }
ReturnValue_t exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST;
ReturnValue_t result = containers::KEY_DOES_NOT_EXIST;
if (findIndex(key) < _size) {
result = returnvalue::OK;
}
@ -103,7 +98,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t erase(Iterator* iter) {
uint32_t i;
if ((i = findIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST;
return containers::KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;
@ -114,7 +109,7 @@ class FixedMap : public SerializeIF {
ReturnValue_t erase(key_t key) {
uint32_t i;
if ((i = findIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST;
return containers::KEY_DOES_NOT_EXIST;
}
theMap[i] = theMap[_size - 1];
--_size;

View File

@ -0,0 +1,14 @@
#ifndef FSFW_CONTAINER_DEFINITIONS_H_
#define FSFW_CONTAINER_DEFINITIONS_H_
#include "fsfw/retval.h"
namespace containers {
static const ReturnValue_t KEY_ALREADY_EXISTS = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x01);
static const ReturnValue_t MAP_FULL = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = returnvalue::makeCode(CLASS_ID::FIXED_MAP, 0x03);
static const ReturnValue_t LIST_FULL = returnvalue::makeCode(CLASS_ID::ARRAY_LIST, 0x01);
} // namespace containers
#endif /* FSFW_CONTAINER_DEFINITIONS_H_ */

View File

@ -13,9 +13,7 @@ ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
submode(SUBMODE_NONE),
modeHelper(this),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
}
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -570,10 +570,6 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
CommandMessage reply;
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);
} else {
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
@ -829,8 +825,6 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
errorPrint = "Dataset not found";
} else if (error == POOLOBJECT_NOT_FOUND) {
errorPrint = "Pool Object not found";
} else if (error == WRONG_HK_PACKET_TYPE) {
errorPrint = "Wrong Packet Type";
} else if (error == returnvalue::FAILED) {
if (outputType == sif::OutputTypes::OUT_WARNING) {
errorPrint = "Generic Warning";

View File

@ -162,7 +162,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
object_id_t getCreatorObjectId();
bool getReportingEnabled() const;
void setReportingEnabled(bool enabled);
/**
* Returns the current periodic HK generation interval this set
@ -190,6 +189,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
* Used for periodic generation.
*/
bool reportingEnabled = false;
void setReportingEnabled(bool enabled);
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
uint8_t nonDiagIntervalFactor = 5);

View File

@ -26,7 +26,11 @@ void AssemblyBase::performChildOperation() {
void AssemblyBase::startTransition(Mode_t mode, Submode_t 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) {
@ -73,10 +77,9 @@ bool AssemblyBase::handleChildrenChangedHealth() {
}
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
triggerEvent(TRYING_RECOVERY, iter->first, 0);
triggerEvent(TRYING_RECOVERY);
recoveryState = RECOVERY_STARTED;
recoveringDevice = iter;
// The user needs to take care of commanding the children off in commandChildren
doStartTransition(targetMode, targetSubmode);
} else {
triggerEvent(CHILD_CHANGED_HEALTH);
@ -225,9 +228,6 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
bool AssemblyBase::checkAndHandleRecovery() {
switch (recoveryState) {
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;
recoveryOffTimer.resetTimer();
return true;
@ -266,11 +266,3 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
modeHelper.setForced(true);
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);
}
}

View File

@ -12,8 +12,7 @@
* Documentation: Dissertation Baetz p.156, 157.
*
* 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
* manage the mode keeping and recovery of non-redundant devices
* otherwise be needed for the handling of redundant devices.
*
* The template class monitors mode and health state of its children
* and checks availability of devices on every detected change.
@ -27,9 +26,11 @@
*
* 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.
* (This will call the function in SubsystemBase)
*
*/
class AssemblyBase : public SubsystemBase {
public:
@ -46,10 +47,9 @@ class AssemblyBase : public SubsystemBase {
protected:
/**
* Command children to reach [mode,submode] combination. Can be done by setting
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
* a recovery might be on-going and the device needs to be commanded to off first.
* Command children to reach [mode,submode] combination
* Can be done by setting #commandsOutstanding correctly,
* or using executeTable()
* @param mode
* @param submode
* @return
@ -120,19 +120,8 @@ class AssemblyBase : public SubsystemBase {
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
/**
* @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;
virtual void performChildOperation();
/**
* This function handles changed mode or health states of children
* @return
*/
bool handleChildrenChanged();
/**
@ -145,37 +134,12 @@ class AssemblyBase : public SubsystemBase {
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();
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);
/**
* 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 bool isInTransition();
@ -196,7 +160,7 @@ class AssemblyBase : public SubsystemBase {
* Manages recovery of a device
* @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.
@ -204,8 +168,6 @@ class AssemblyBase : public SubsystemBase {
* @param objectId Must be a registered child.
*/
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
};
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */

View File

@ -22,6 +22,8 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
size_t cmdQueueSize)
: SystemObject(setObjectId),
mode(MODE_OFF),
submode(SUBMODE_NONE),
wiretappingMode(OFF),
storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication),
@ -36,13 +38,10 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
defaultFDIRUsed(fdirInstance == nullptr),
switchOffWasReported(false),
childTransitionDelay(5000),
mode(MODE_OFF),
submode(SUBMODE_NONE),
transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceSubMode(SUBMODE_NONE) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end();
@ -50,6 +49,9 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
"Invalid cookie");
}
if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
}
}
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
@ -127,18 +129,6 @@ ReturnValue_t DeviceHandlerBase::initialize() {
if (result != returnvalue::OK) {
return result;
}
if (this->fdirInstance == nullptr) {
this->fdirInstance =
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
}
if (this->parent != objects::NO_OBJECT) {
HasModesIF* modeIF = ObjectManager::instance()->get<HasModesIF>(this->parent);
HasHealthIF* healthIF = ObjectManager::instance()->get<HasHealthIF>(this->parent);
if (modeIF != nullptr and healthIF != nullptr) {
setParentQueue(modeIF->getCommandQueue());
}
}
communicationInterface =
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
@ -331,8 +321,7 @@ void DeviceHandlerBase::doStateMachine() {
if (mode != currentMode) {
break;
}
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
uint32_t currentUptime = Clock::getUptime_ms();
if (currentUptime - timeoutStart >= childTransitionDelay) {
#if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0
char printout[60];
@ -356,29 +345,31 @@ void DeviceHandlerBase::doStateMachine() {
setMode(_MODE_WAIT_ON);
break;
case _MODE_WAIT_ON: {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
uint32_t currentUptime = Clock::getUptime_ms();
if (powerSwitcher != nullptr and
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(_MODE_POWER_DOWN);
callChildStatemachine();
break;
}
ReturnValue_t switchState = getStateOfSwitches();
if ((switchState == PowerSwitchIF::SWITCH_ON) || (switchState == NO_SWITCH)) {
// NOTE: TransitionSourceMode and -SubMode are set by handleCommandedModeTransition
childTransitionFailure = CHILD_TIMEOUT;
transitionSourceMode = _MODE_SHUT_DOWN;
transitionSourceSubMode = SUBMODE_NONE;
setMode(_MODE_START_UP);
callChildStatemachine();
}
} break;
case _MODE_WAIT_OFF: {
uint32_t currentUptime = Clock::getUptime_ms();
if (powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
setMode(MODE_ERROR_ON);
@ -573,30 +564,17 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
}
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
/**
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
*/
if (newMode == MODE_ON and continueToNormal) {
continueToNormal = false;
mode = _MODE_TO_NORMAL;
return;
}
/* TODO: This will probably be done by the LocalDataPoolManager now */
// changeHK(mode, submode, false);
submode = newSubmode;
mode = newMode;
modeChanged();
setNormalDatapoolEntriesInvalid();
if (newMode == MODE_OFF) {
disableCommandsAndReplies();
}
if (!isTransitionalMode()) {
// clear this flag when a non-transitional Mode is reached to be safe
continueToNormal = false;
modeHelper.modeChanged(newMode, newSubmode);
announceMode(false);
}
Clock::getUptime(&timeoutStart);
timeoutStart = Clock::getUptime_ms();
if (mode == MODE_OFF and thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read();
@ -1077,7 +1055,8 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
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 :-)
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
// - Modularization?
@ -1089,10 +1068,11 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
return TRANS_NOT_ALLOWED;
}
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
return TRANS_NOT_ALLOWED;
}
// Do not check thermal state for MODE_RAW
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
(thermalSet != nullptr)) {
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
ReturnValue_t result = thermalSet->read();
if (result == returnvalue::OK) {
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
@ -1107,7 +1087,6 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
}
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
continueToNormal = false;
switch (commandedMode) {
case MODE_ON:
handleTransitionToOnMode(commandedMode, commandedSubmode);
@ -1137,9 +1116,8 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
case MODE_NORMAL:
if (mode != MODE_OFF) {
setTransition(MODE_NORMAL, commandedSubmode);
} else { // mode is off
continueToNormal = true;
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
} else {
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
}
break;
}
@ -1297,7 +1275,6 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
if (iter->second.command != deviceCommandMap.end()) {
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
// This may fail, but we'll ignore the fault.
if (queueId != NO_COMMANDER) {
// This may fail, but we'll ignore the fault.
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
@ -1476,8 +1453,6 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
uint32_t parameter) {}
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
void DeviceHandlerBase::performOperationHook() {}
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
@ -1500,7 +1475,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
this->poolManager.initializeAfterTaskCreation();
if (setStartupImmediately) {
startTransition(MODE_ON, getInitialSubmode());
startTransition(MODE_ON, SUBMODE_NONE);
}
return returnvalue::OK;
}
@ -1584,48 +1559,3 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
}
return commandIter->second.sendReplyTo;
}
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
void DeviceHandlerBase::setParent(object_id_t parent) { this->parent = parent; }
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
this->powerSwitcher = switcher;
}
Mode_t DeviceHandlerBase::getMode() {
return mode;
}
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::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;
}

View File

@ -23,7 +23,6 @@
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
#include "fsfw/tasks/ExecutableObjectIF.h"
#include "fsfw/tasks/PeriodicTaskIF.h"
#include "fsfw/util/dataWrapper.h"
namespace Factory {
void setStaticFrameworkObjectIds();
@ -103,57 +102,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
void setCustomFdir(FailureIsolationBase *fdir);
void setParent(object_id_t parent);
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;
//! This is a transitional state which can not be commanded. The switch has
//! been commanded off and is off now. This state is only to do an RMAP
//! cycle once more where the doSendRead() function will set the mode to
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
void setHkDestination(object_id_t hkDestination);
/**
@ -447,8 +395,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
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
* like SPI sensors to identify the last sent command.
@ -517,14 +463,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* @brief This is a helper method to insert replies in the reply map.
* @param deviceCommand Identifier of the reply to add.
* @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
* 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
* #updatePeriodicReply
* 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
* #updatePeriodicReply
* @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
* when expired
* to provide a pointer to a Countdown object which will signal the timeout
* when expired
* @return - @c returnvalue::OK when the command was successfully inserted,
* - @c returnvalue::FAILED else.
*/
@ -709,12 +655,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 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:
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@ -744,18 +684,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
size_t rawPacketLen = 0;
/**
* Get the current mode
*
* set via setMode()
* The mode the device handler is currently in.
* This should never be changed directly but only with setMode()
*/
Mode_t getMode();
Mode_t mode;
/**
* Get the current Submode
*
* set via setMode()
* The submode the device handler is currently in.
* This should never be changed directly but only with setMode()
*/
Submode_t getSubmode();
Submode_t submode;
/** This is the counter value from performOperation(). */
uint8_t pstStep = 0;
@ -836,18 +773,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* This is used to keep track of pending replies.
*/
struct DeviceReplyInfo {
//! For Command-Reply combinations:
//! The maximum number of cycles the handler should wait for a reply
//! 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;
//! This variable will be set to #maxDelayCycles if a reply is expected.
//! For non-periodic replies without a command, this variable is unused.
//! A runtime value of 0 means there is no reply is currently expected.
//! The currently remaining cycles the handler should wait for a reply,
//! 0 means there is no reply expected
uint16_t delayCycles;
size_t replyLen = 0; //!< Expected size of the reply.
//! if this is !=0, the delayCycles will not be reset to 0 but to
@ -903,7 +833,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
/** Pointer to the used FDIR instance. If not provided by child,
* default class is instantiated. */
FailureIsolationBase *fdirInstance;
object_id_t parent = objects::NO_OBJECT;
//! To correctly delete the default instance.
bool defaultFDIRUsed;
@ -944,8 +873,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* 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,
* which can be deduced from the current mode (which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
* which can be deduced from the current mode which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
*
* The intended target submode is already set.
* The origin submode can be read in subModeFrom.
@ -1191,22 +1120,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
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:
/**
* State a cookie is in.
@ -1257,18 +1170,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
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
*
@ -1286,15 +1187,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
*/
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
*/
@ -1363,6 +1255,21 @@ class DeviceHandlerBase : public DeviceHandlerIF,
* - if the action was successful, the reply timout counter is initialized
*/
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.
@ -1416,11 +1323,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
ReturnValue_t errorCode = returnvalue::FAILED,
const char *errorPrint = nullptr);
/**
* @brief Disables all commands and replies when device is set to MODE_OFF
*/
void disableCommandsAndReplies();
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */

View File

@ -29,7 +29,6 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
switch (event->getEvent()) {
case HasModesIF::MODE_TRANSITION_FAILED:
case HasModesIF::OBJECT_IN_INVALID_MODE:
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
// We'll try a recovery as long as defined in MAX_REBOOT.
// Might cause some AssemblyBase cycles, so keep number low.
handleRecovery(event->getEvent());

View File

@ -24,6 +24,9 @@ class DeviceHandlerIF {
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
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_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
//! can be commanded, which tries to switch off the device again.
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 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 MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
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;

View File

@ -1,10 +1,9 @@
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
#include "fsfw/action/HasActionsIF.h"
#include "fsfw/objectmanager/SystemObjectIF.h"
#include "fsfw/serialize/SerializeIF.h"
#include "fsfw/util/dataWrapper.h"
#include "../action/HasActionsIF.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../serialize/SerializeIF.h"
class DeviceTmReportingWrapper : public SerializeIF {
public:

View File

@ -8,9 +8,7 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
parentQueue(parentQueue),
commandQueue(),
healthHelper(this, setObjectId) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(3);
}
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }

View File

@ -18,12 +18,12 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
EventManager::EventManager(object_id_t setObjectId)
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
EventMessage::EVENT_MESSAGE_SIZE);
}
EventManager::~EventManager() {
listenerList.clear();
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
MutexFactory::instance()->deleteMutex(mutex);
}
@ -47,20 +47,9 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
void EventManager::notifyListeners(EventMessage* message) {
lockMutex();
for (auto& listener : listenerList) {
if (listener.second.match(message)) {
ReturnValue_t result =
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
<< result << std::setfill(' ') << std::endl;
#else
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
listener.first, result);
#endif
}
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
if (iter->second.match(message)) {
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
}
}
unlockMutex();
@ -73,9 +62,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
if (!result.second) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
}
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
return subscribeToEventRange(listener, event);
}
@ -206,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 */

View File

@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
MessageQueueId_t getEventReportQueue();
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
@ -43,7 +44,6 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
bool reporterInverted = false);
ReturnValue_t performOperation(uint8_t opCode);
void printListeners();
protected:
MessageQueueIF* eventReportQueue = nullptr;

View File

@ -18,6 +18,7 @@ class EventManagerIF {
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
bool forwardAllButSelected = false) = 0;
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;

View File

@ -33,7 +33,6 @@ enum : uint8_t {
PUS_SERVICE_23 = 103,
MGM_LIS3MDL = 106,
MGM_RM3100 = 107,
CFDP = 108,
FW_SUBSYSTEM_ID_RANGE
};

View File

@ -9,9 +9,8 @@
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
uint8_t messageDepth, uint8_t parameterDomainBase)
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
eventQueue = QueueFactory::instance()->createMessageQueue(
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
eventQueue =
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
}
FailureIsolationBase::~FailureIsolationBase() {
@ -24,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() {
#endif
return;
}
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
manager->unregisterListener(eventQueue->getId());
QueueFactory::instance()->deleteMessageQueue(eventQueue);
}
@ -62,12 +61,11 @@ ReturnValue_t FailureIsolationBase::initialize() {
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
if (parentIF == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "FailureIsolationBase::intialize: Parent object "
<< "invalid" << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
#else
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl;
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
#endif
return ObjectManagerIF::CHILD_INIT_FAILED;
return returnvalue::FAILED;

View File

@ -12,12 +12,13 @@
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
public:
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 = MAKE_EVENT(1, severity::INFO);
//! FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
//! FDIR turns off device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
static const Event FDIR_CHANGED_STATE =
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
//!< (oldState) to par1 (newState).
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
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); //!< FDIR turns off device. Par1: event that caused recovery.
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);

View File

@ -40,7 +40,6 @@ class HasFileSystemIF {
//! [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_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);
//! [EXPORT] : File system is currently busy

View File

@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
MatchTree(iterator root, uint8_t maxDepth = -1)
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
virtual ~MatchTree() {}
virtual ~MatchTree() { clear(); }
virtual bool match(T number) override { return matchesTree(number); }
bool matchesTree(T number) {
iterator iter = this->begin();
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
return cleanUpElement(position);
}
void clear() {
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
if (localRoot == nullptr) {
return;
}
Node* node = localRoot->left;
while (true) {
if (node->left != nullptr) {
node = node->left;
continue;
}
if (node->right != nullptr) {
node = node->right;
continue;
}
if (node->parent == nullptr) {
// this is the root node with no children
if (node->value != nullptr) {
cleanUpElement(iterator(node));
}
return;
}
// leaf
{
Node* parent = node->parent;
if (parent->left == node) {
parent->left = nullptr;
} else {
parent->right = nullptr;
}
cleanUpElement(iterator(node));
node = parent;
}
}
}
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
bool matchSubtree(iterator iter, T number) {

View File

@ -1,8 +1,8 @@
#include "fsfw/globalfunctions/timevalOperations.h"
timeval& operator+=(timeval& lhs, const timeval& rhs) {
int64_t sum = lhs.tv_sec * 1000000. + lhs.tv_usec;
sum += rhs.tv_sec * 1000000. + rhs.tv_usec;
int64_t sum = static_cast<int64_t>(lhs.tv_sec) * 1000000. + lhs.tv_usec;
sum += static_cast<int64_t>(rhs.tv_sec) * 1000000. + rhs.tv_usec;
lhs.tv_sec = sum / 1000000;
lhs.tv_usec = sum - lhs.tv_sec * 1000000;
return lhs;

View File

@ -16,24 +16,26 @@ class HasHealthIF {
};
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3);
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
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 CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
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 = MAKE_EVENT(9, severity::LOW);
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
//! Recovery is ongoing. Comes twice during recovery.
//! P1: 0 for the first, 1 for the second event. P2: 0
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
//! Recovery was completed. Not necessarily successful. No parameters.
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
static const Event OVERWRITING_HEALTH =
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
//!< satellite alive.
static const Event TRYING_RECOVERY =
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
//!< power-cycle). No parameters.
static const Event RECOVERY_STEP =
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
//!< 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 MessageQueueId_t getCommandQueue() const = 0;

View File

@ -5,7 +5,11 @@
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId)
: objectId(objectId), owner(owner) {}
HealthHelper::~HealthHelper() { healthTable->removeObject(objectId); }
HealthHelper::~HealthHelper() {
if (healthTable != nullptr) {
healthTable->removeObject(objectId);
}
}
ReturnValue_t HealthHelper::handleHealthCommand(CommandMessage* message) {
switch (message->getCommand()) {

View File

@ -6,8 +6,6 @@
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
mutex = MutexFactory::instance()->createMutex();
;
mapIterator = healthMap.begin();
}

View File

@ -7,16 +7,17 @@
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
: SystemObject(setObjectId),
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex();
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex);
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
this->diagnosticPrintout = enable;
@ -38,14 +39,15 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
<< newStoreHits << std::endl;
<< "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl;
#else
sif::printDebug(
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
"| %lu\n",
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
static_cast<unsigned int>(newStoreHits));
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
#endif
}
}

View File

@ -34,7 +34,7 @@ class CommandMessageIF {
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
//! 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);
virtual ~CommandMessageIF(){};

View File

@ -19,33 +19,32 @@ class HasModesIF {
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
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 = MAKE_EVENT(0, severity::INFO);
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
static const Event CHANGING_MODE =
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
//!< p2: target submode
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 MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
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 = MAKE_EVENT(5, severity::LOW);
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
//! p1: target mode. p2: target submode
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
static const Event OBJECT_IN_INVALID_MODE =
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
//!< mode it should never be in.
static const Event FORCING_MODE = MAKE_EVENT(
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
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
//! sent by the device handler itself, but direct commands van be commanded and will be
//! interpreted
static constexpr Mode_t MODE_ON = 1;
//! The device is powered off. The only command accepted in this mode is a mode change to on.
static constexpr Mode_t MODE_OFF = 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;
static const Mode_t MODE_ON =
1; //!< The device is powered and ready to perform operations. In this mode, no commands are
//!< sent by the device handler itself, but direct commands van be commanded and will be
//!< interpreted
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
//!< this mode is a mode change to on.
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
virtual ~HasModesIF() {}
virtual MessageQueueId_t getCommandQueue() const = 0;

View File

@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
ObjectManager::ObjectManager() = default;
void ObjectManager::clear() {
if (objManagerInstance != nullptr) {
delete objManagerInstance;
objManagerInstance = nullptr;
}
}
ObjectManager::~ObjectManager() {
for (auto const& iter : objectList) {
delete iter.second;
teardown = true;
for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
delete iter->second;
}
}
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
}
ReturnValue_t ObjectManager::remove(object_id_t id) {
// this function is called during destruction of System Objects
// disabeld for teardown to avoid iterator invalidation and
// double free
if (teardown) {
return returnvalue::OK;
}
if (this->getSystemObject(id) != nullptr) {
this->objectList.erase(id);
#if FSFW_CPP_OSTREAM_ENABLED == 1
@ -95,16 +109,13 @@ void ObjectManager::initialize() {
for (auto const& it : objectList) {
result = it.second->initialize();
if (result != returnvalue::OK) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
object_id_t var = it.first;
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
<< std::dec << std::setfill(' ') << std::endl;
#else
sif::printError(
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
it.first);
#endif
<< std::setfill('0') << var
<< " failed to "
"initialize with code 0x"
<< result << std::dec << std::setfill(' ') << std::endl;
#endif
errorCount++;
}

View File

@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF {
using produce_function_t = void (*)(void* args);
/**
* Returns the single instance of TaskFactory.
* Returns the single instance of ObjectManager.
* The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance.
*/
static ObjectManager* instance();
/**
* Deletes the single instance of ObjectManager
*/
static void clear();
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
template <typename T>
@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF {
*/
std::map<object_id_t, SystemObjectIF*> objectList;
static ObjectManager* objManagerInstance;
// used when the OM itself is deleted to modify behaviour of remove()
// to avoid iterator invalidation and double free
bool teardown = false;
};
// Documentation can be found in the class method declaration above

View File

@ -1,10 +1,13 @@
# Check the OS_FSFW variable
if(FSFW_OSAL MATCHES "freertos")
add_subdirectory(freertos)
set(FSFW_OSAL_FREERTOS 1)
elseif(FSFW_OSAL MATCHES "rtems")
add_subdirectory(rtems)
set(FSFW_OSAL_RTEMS 1)
elseif(FSFW_OSAL MATCHES "linux")
add_subdirectory(linux)
set(FSFW_OSAL_LINUX 1)
elseif(FSFW_OSAL MATCHES "host")
add_subdirectory(host)
if(WIN32)
@ -13,18 +16,17 @@ elseif(FSFW_OSAL MATCHES "host")
# We still need to pull in some Linux specific sources
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
endif()
set(FSFW_OSAL_HOST 1)
else()
message(
WARNING
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS
if(WIN32)
add_subdirectory(host)
add_subdirectory(windows)
set(FSFW_OSAL_HOST 1)
elseif(UNIX)
add_subdirectory(linux)
set(FSFW_OSAL_LINUX 1)
else()
# MacOS or other OSes have not been tested yet / are not supported.
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
@ -33,3 +35,5 @@ else()
endif()
add_subdirectory(common)
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)

View File

@ -40,7 +40,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF {
void refreshTaskHandle();
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override;
uint32_t timeoutMs = 0) override;
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);

View File

@ -51,7 +51,7 @@ class BinarySemaphore : public SemaphoreIF {
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
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.

View File

@ -11,19 +11,6 @@
// TODO sanitize input?
// 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) {
timeval uptime = getUptime();
@ -44,81 +31,15 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return returnvalue::OK;
}
timeval Clock::getUptime() {
TickType_t ticksSinceStart = xTaskGetTickCount();
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() {
// timeval uptime = getUptime();
// 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;
}

View File

@ -34,7 +34,7 @@ class CountingSemaphoreUsingTask : public SemaphoreIF {
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
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

View File

@ -56,7 +56,9 @@ ReturnValue_t FixedTimeslotTask::startTask() {
// start time for the first entry.
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.
uint32_t intervalMs = slotListIter->pollingTimeMs;

View File

@ -22,7 +22,7 @@ ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
return MutexIF::MUTEX_NOT_FOUND;
}
// 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) {
timeout = 0;
} else if (timeoutType == TimeoutType::WAITING) {

View File

@ -3,16 +3,16 @@
void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); }
void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::TASK) {
if (callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device
vRequestContextSwitchFromISR();
} else {
vRequestContextSwitchFromTask();
}
// if (callContext == CallContext::ISR) {
// // This function depends on the partmacro.h definition for the specific device
// vRequestContextSwitchFromISR();
// } else {
vRequestContextSwitchFromTask();
// }
}
TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); }
size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) {
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
}
// size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) {
// return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
// }

View File

@ -11,7 +11,7 @@
* Architecture dependant portmacro.h function call.
* Should be implemented in bsp.
*/
extern "C" void vRequestContextSwitchFromISR();
// extern "C" void vRequestContextSwitchFromISR();
/*!
* 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
* words.
*/
size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr);
// size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr);
}; // namespace TaskManagement

View File

@ -15,27 +15,6 @@
using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getTicksPerSecond: Not implemented for host OSAL" << std::endl;
#else
sif::printWarning("Clock::getTicksPerSecond: Not implemented for host OSAL\n");
#endif
/* To avoid division by zero */
return 1;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
/* I don't know why someone would need to set a clock which is probably perfectly fine on a
host system with internet access so this is not implemented for now. */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
#else
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
#endif
return returnvalue::OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
/* I don't know why someone would need to set a clock which is probably perfectly fine on a
host system with internet access so this is not implemented for now. */
@ -66,6 +45,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
time->tv_usec = timeUnix.tv_nsec / 1000.0;
return returnvalue::OK;
#else
#warning Clock::getClock_timeval() not implemented for your platform
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
#else
@ -75,15 +55,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
#endif
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
if (time == nullptr) {
return returnvalue::FAILED;
}
using namespace std::chrono;
*time = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
return returnvalue::OK;
}
timeval Clock::getUptime() {
timeval timeval;
#if defined(PLATFORM_WIN)
@ -100,6 +71,7 @@ timeval Clock::getUptime() {
timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6);
}
#else
#warning Clock::getUptime() not implemented for your platform
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
@ -107,66 +79,3 @@ timeval Clock::getUptime() {
return timeval;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return returnvalue::OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return returnvalue::OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
/* Do some magic with chrono (C++20!) */
/* Right now, the library doesn't have the new features to get the required values yet.
so we work around that for now. */
auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now);
ReturnValue_t result = checkOrCreateClockMutex();
if (result != returnvalue::OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct tm* timeInfo;
timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon + 1;
time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count();
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_tm.tm_isdst = 0;
time_t seconds = timegm(&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;
}

View File

@ -10,26 +10,6 @@
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
uint32_t Clock::getTicksPerSecond() {
uint32_t ticks = sysconf(_SC_CLK_TCK);
return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timespec timeUnix{};
timeval timeTimeval{};
convertTimeOfDayToTimeval(time, &timeTimeval);
timeUnix.tv_sec = timeTimeval.tv_sec;
timeUnix.tv_nsec = (__syscall_slong_t)timeTimeval.tv_usec * 1000;
int status = clock_settime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
// TODO errno
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
timespec timeUnix{};
timeUnix.tv_sec = time->tv_sec;
@ -53,104 +33,12 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval timeVal{};
ReturnValue_t result = getClock_timeval(&timeVal);
if (result != returnvalue::OK) {
return result;
}
*time = static_cast<uint64_t>(timeVal.tv_sec) * 1e6 + timeVal.tv_usec;
return returnvalue::OK;
}
timeval Clock::getUptime() {
timeval uptime{};
auto result = getUptime(&uptime);
if (result != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Clock::getUptime: Error getting uptime" << std::endl;
#endif
}
return uptime;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
// TODO This is not posix compatible and delivers only seconds precision
// Linux specific file read but more precise.
timeval uptime{0,0};
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
uptime->tv_sec = uptimeSeconds;
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6);
uptime.tv_sec = uptimeSeconds;
uptime.tv_usec = uptimeSeconds * (double)1e6 - (uptime.tv_sec * 1e6);
}
return returnvalue::OK;
}
// Wait for new FSFW Clock function delivering seconds uptime.
// uint32_t Clock::getUptimeSeconds() {
// //TODO This is not posix compatible and delivers only seconds precision
// struct sysinfo sysInfo;
// int result = sysinfo(&sysInfo);
// if(result != 0){
// return returnvalue::FAILED;
// }
// return sysInfo.uptime;
//}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime{};
ReturnValue_t result = getUptime(&uptime);
if (result != returnvalue::OK) {
return result;
}
*uptimeMs = uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
return returnvalue::OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timespec timeUnix{};
int status = clock_gettime(CLOCK_REALTIME, &timeUnix);
if (status != 0) {
// TODO errno
return returnvalue::FAILED;
}
ReturnValue_t result = checkOrCreateClockMutex();
if (result != returnvalue::OK) {
return result;
}
MutexGuard helper(timeMutex);
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
struct std::tm* timeInfo;
timeInfo = gmtime(&timeUnix.tv_sec);
time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon + 1;
time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec;
time->usecond = timeUnix.tv_nsec / 1000.0;
return returnvalue::OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
std::tm fromTm{};
// Note: Fails for years before AD
fromTm.tm_year = from->year - 1900;
fromTm.tm_mon = from->month - 1;
fromTm.tm_mday = from->day;
fromTm.tm_hour = from->hour;
fromTm.tm_min = from->minute;
fromTm.tm_sec = from->second;
fromTm.tm_isdst = 0;
to->tv_sec = timegm(&fromTm);
to->tv_usec = from->usecond;
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;
}
return uptime;
}

View File

@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs*
attributes.mq_msgsize = maxMessageSize;
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
// Set the name of the queue. The slash is mandatory!
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
sprintf(name, "/FSFW_MQ%u", queueCounter++);
// Create a nonblocking queue if the name is available (the queue is read
// and writable for the owner as well as the group)

36
src/fsfw/osal/osal.h.in Normal file
View File

@ -0,0 +1,36 @@
#pragma once
namespace osal {
enum osalTarget{
HOST,
LINUX,
WINDOWS,
FREERTOS,
RTEMS,
};
#cmakedefine FSFW_OSAL_HOST
#cmakedefine FSFW_OSAL_LINUX
#cmakedefine FSFW_OSAL_WINDOWS
#cmakedefine FSFW_OSAL_FREERTOS
#cmakedefine FSFW_OSAL_RTEMS
constexpr osalTarget getTarget() {
#ifdef FSFW_OSAL_HOST
return HOST;
#endif
#ifdef FSFW_OSAL_LINUX
return LINUX;
#endif
#ifdef FSFW_OSAL_WINDOWS
return WINDOWS;
#endif
#ifdef FSFW_OSAL_FREERTOS
return FREERTOS;
#endif
#ifdef FSFW_OSAL_RTEMS
return RTEMS;
#endif
}
};

View File

@ -2,6 +2,8 @@
#include <rtems/rtems/sem.h>
//TODO
BinarySemaphore::BinarySemaphore() {}
BinarySemaphore::~BinarySemaphore() {}

View File

@ -6,20 +6,21 @@
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/osal/rtems/RtemsBasic.h"
uint32_t Clock::getTicksPerSecond(void) {
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second);
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
ReturnValue_t Clock::setClock(const timeval* time) {
TimeOfDay_t time_tod;
ReturnValue_t result = convertTimevalToTimeOfDay(time, &time_tod);
if (result != returnvalue::OK) {
return result;
}
rtems_time_of_day timeRtems;
timeRtems.year = time->year;
timeRtems.month = time->month;
timeRtems.day = time->day;
timeRtems.hour = time->hour;
timeRtems.minute = time->minute;
timeRtems.second = time->second;
timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6;
timeRtems.year = time_tod.year;
timeRtems.month = time_tod.month;
timeRtems.day = time_tod.day;
timeRtems.hour = time_tod.hour;
timeRtems.minute = time_tod.minute;
timeRtems.second = time_tod.second;
timeRtems.ticks = static_cast<uint64_t>(time_tod.usecond) * rtems_clock_get_ticks_per_second() / 1e6;
rtems_status_code status = rtems_clock_set(&timeRtems);
switch (status) {
case RTEMS_SUCCESSFUL:
@ -33,27 +34,6 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
}
}
ReturnValue_t Clock::setClock(const timeval* time) {
timespec newTime;
newTime.tv_sec = time->tv_sec;
if (time->tv_usec < 0) {
// better returnvalue.
return returnvalue::FAILED;
}
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
ISR_lock_Context context;
_TOD_Lock();
_TOD_Acquire(&context);
Status_Control status = _TOD_Set(&newTime, &context);
_TOD_Unlock();
if (status == STATUS_SUCCESSFUL) {
return returnvalue::OK;
}
// better returnvalue
return returnvalue::FAILED;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
// Callable from ISR
rtems_status_code status = rtems_clock_get_tod_timeval(time);
@ -67,86 +47,13 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
}
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
timeval Clock::getUptime() {
// According to docs.rtems.org for rtems 5 this method is more accurate than
// rtems_clock_get_ticks_since_boot
timeval time_timeval;
timespec time;
rtems_status_code status = rtems_clock_get_uptime(&time);
uptime->tv_sec = time.tv_sec;
time.tv_nsec = time.tv_nsec / 1000;
uptime->tv_usec = time.tv_nsec;
switch (status) {
case RTEMS_SUCCESSFUL:
return returnvalue::OK;
default:
return returnvalue::FAILED;
}
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
// This counter overflows after 50 days
*uptimeMs = rtems_clock_get_ticks_since_boot();
return returnvalue::OK;
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval temp_time;
rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time);
*time = ((uint64_t)temp_time.tv_sec * 1000000) + temp_time.tv_usec;
switch (returnValue) {
case RTEMS_SUCCESSFUL:
return returnvalue::OK;
default:
return returnvalue::FAILED;
}
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
/* For all but the last field, the struct will be filled with the correct values */
rtems_time_of_day timeRtems;
rtems_status_code status = rtems_clock_get_tod(&timeRtems);
switch (status) {
case RTEMS_SUCCESSFUL: {
/* The last field now contains the RTEMS ticks of the seconds from 0
to rtems_clock_get_ticks_per_second() minus one.
We calculate the microseconds accordingly */
time->day = timeRtems.day;
time->hour = timeRtems.hour;
time->minute = timeRtems.minute;
time->month = timeRtems.month;
time->second = timeRtems.second;
time->usecond =
static_cast<float>(timeRtems.ticks) / rtems_clock_get_ticks_per_second() * 1e6;
time->year = timeRtems.year;
return returnvalue::OK;
}
case RTEMS_NOT_DEFINED:
/* System date and time is not set */
return returnvalue::FAILED;
case RTEMS_INVALID_ADDRESS:
/* time_buffer is NULL */
return returnvalue::FAILED;
default:
return returnvalue::FAILED;
}
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
// Fails in 2038..
rtems_time_of_day timeRtems;
timeRtems.year = from->year;
timeRtems.month = from->month;
timeRtems.day = from->day;
timeRtems.hour = from->hour;
timeRtems.minute = from->minute;
timeRtems.second = from->second;
timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6;
to->tv_sec = _TOD_To_seconds(&timeRtems);
to->tv_usec = from->usecond;
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;
}
time_timeval.tv_sec = time.tv_sec;
time_timeval.tv_usec = time.tv_nsec / 1000;
return time_timeval;
}

View File

@ -93,8 +93,8 @@ ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size, size_t maxSize
streamEndianness);
}
uint32_t CpuUsage::getSerializedSize() const {
uint32_t size = 0;
size_t CpuUsage::getSerializedSize() const {
size_t size = 0;
size += sizeof(timeSinceLastReset);
size += SerialArrayListAdapter<ThreadData>::getSerializedSize(&threadData);
@ -136,8 +136,8 @@ ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size, si
return returnvalue::OK;
}
uint32_t CpuUsage::ThreadData::getSerializedSize() const {
uint32_t size = 0;
size_t CpuUsage::ThreadData::getSerializedSize() const {
size_t size = 0;
size += sizeof(id);
size += MAX_LENGTH_OF_THREAD_NAME;

View File

@ -35,10 +35,9 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) {
return OUT_OF_PROXIES;
case INTERNAL_ERROR_INVALID_GLOBAL_ID:
return INVALID_GLOBAL_ID;
#ifndef STM32H743ZI_NUCLEO
case INTERNAL_ERROR_BAD_STACK_HOOK:
return BAD_STACK_HOOK;
#endif
//TODO this one is not there anymore in rtems-6 (5 as well?)
//case INTERNAL_ERROR_BAD_STACK_HOOK:
// return BAD_STACK_HOOK;
// case INTERNAL_ERROR_BAD_ATTRIBUTES:
// return BAD_ATTRIBUTES;
// case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY:

View File

@ -18,7 +18,9 @@ SemaphoreFactory* SemaphoreFactory::instance() {
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
return new BinarySemaphore();
return nullptr;
//TODO
//return new BinarySemaphore();
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, uint8_t initCount,

View File

@ -66,8 +66,7 @@ class HasParametersIF {
* @param newValues
* @param startAtIndex Linear index, runs left to right, top to bottom for
* matrix indexes.
* @return returnvalue::OK if parameter is valid and a set function of the parameter wrapper was
* called.
* @return
*/
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
ParameterWrapper *parameterWrapper,

View File

@ -211,13 +211,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (data == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
"data pointer not set"
<< std::endl;
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
#else
sif::printWarning(
"ParameterWrapper::copyFrom: Called on read-only variable "
"or data pointer not set\n");
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return READONLY;
@ -226,9 +222,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (from->readonlyData == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return SOURCE_NOT_SET;
@ -237,9 +233,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (type != from->type) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return DATATYPE_MISSMATCH;
@ -249,9 +245,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
if (rows == 0 or columns == 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return COLUMN_OR_ROWS_ZERO;

View File

@ -29,9 +29,9 @@ class PowerSwitchIF {
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
//!< Someone detected that a switch went off which shouldn't. Severity:
//!< Low, Parameter1: switchId1, Parameter2: switchId2
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
static const Event SWITCH_WENT_OFF = MAKE_EVENT(
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
//!< Low, Parameter1: switchId1, Parameter2: switchId2
/**
* send a direct command to the Power Unit to enable/disable the specified switch.
*

View File

@ -41,6 +41,8 @@ class Service11TelecommandScheduling final : public PusServiceBase {
static constexpr ReturnValue_t INVALID_TIME_WINDOW = returnvalue::makeCode(CLASS_ID, 2);
static constexpr ReturnValue_t TIMESHIFTING_NOT_POSSIBLE = returnvalue::makeCode(CLASS_ID, 3);
static constexpr ReturnValue_t INVALID_RELATIVE_TIME = returnvalue::makeCode(CLASS_ID, 4);
static constexpr ReturnValue_t CONTAINED_TC_TOO_SMALL = returnvalue::makeCode(CLASS_ID, 5);
static constexpr ReturnValue_t CONTAINED_TC_CRC_MISSMATCH = returnvalue::makeCode(CLASS_ID, 6);
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_11;

View File

@ -2,9 +2,11 @@
#include <cstddef>
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface.h"
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
@ -77,7 +79,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::performService
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
// does not work in this case as we are deleting the current element here.
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
if (it->first <= static_cast<uint32_t>(tNow.tv_sec)) {
if (it->first <= tNow.tv_sec) {
if (schedulingEnabled) {
// release tc
TmTcMessage releaseMsg(it->second.storeAddr);
@ -171,6 +173,14 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
return returnvalue::FAILED;
}
if (size < PusTcIF::MIN_SIZE) {
return CONTAINED_TC_TOO_SMALL;
}
if (CRC::crc16ccitt(data, size) != 0) {
return CONTAINED_TC_CRC_MISSMATCH;
}
// store currentPacket and receive the store address
store_address_t addr{};
if (tcStore->addData(&addr, data, size) != returnvalue::OK ||

View File

@ -208,17 +208,17 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
ReturnValue_t error = returnvalue::FAILED;
HousekeepingMessage::getHkRequestFailureReply(reply, &error);
failureParameter2 = error;
return returnvalue::FAILED;
return CommandingServiceBase::EXECUTION_COMPLETE;
}
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
<< "reply command " << command << std::endl;
<< "reply command " << command << "!" << std::endl;
#else
sif::printWarning(
"Service3Housekeeping::handleReply: Invalid reply with "
"reply command %hu\n",
"reply command %hu!\n",
command);
#endif
return CommandingServiceBase::INVALID_REPLY;
@ -248,28 +248,19 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
case (HousekeepingMessage::HK_REQUEST_FAILURE): {
break;
}
case (CommandMessage::REPLY_REJECTED): {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
"rejected with error code"
<< reply->getParameter() << std::endl;
#else
#endif
break;
}
default: {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply "
"command "
<< command << "" << std::endl;
<< command << "!" << std::endl;
#else
sif::printWarning(
"Service3Housekeeping::handleUnrequestedReply: Invalid reply with "
"reply command %hu\n",
"reply command %hu!\n",
command);
#endif
break;
return;
}
}
@ -284,7 +275,6 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
"Could not generate reply!\n");
#endif
}
CommandingServiceBase::handleUnrequestedReply(reply);
}
MessageQueueId_t Service3Housekeeping::getHkQueue() const { return commandQueue->getId(); }

View File

@ -13,10 +13,8 @@ Service5EventReporting::Service5EventReporting(PsbParams params, size_t maxNumbe
storeHelper(params.apid),
tmHelper(params.serviceId, storeHelper, sendHelper),
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
auto mqArgs = MqArgs(getObjectId(), static_cast<void*>(this));
psbParams.name = "PUS 5 Event Reporting";
eventQueue = QueueFactory::instance()->createMessageQueue(
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
}
Service5EventReporting::~Service5EventReporting() {
@ -40,6 +38,9 @@ ReturnValue_t Service5EventReporting::performService() {
}
}
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
#endif
return returnvalue::OK;
}

View File

@ -33,13 +33,12 @@ ReturnValue_t Service9TimeManagement::setTime() {
return result;
}
uint32_t formerUptime;
Clock::getUptime(&formerUptime);
// TODO maybe switch to getClock_usecs to report more meaningful data
uint32_t formerUptime = Clock::getUptime_ms();
result = Clock::setClock(&timeToSet);
if (result == returnvalue::OK) {
uint32_t newUptime;
Clock::getUptime(&newUptime);
uint32_t newUptime = Clock::getUptime_ms();
triggerEvent(CLOCK_SET, newUptime, formerUptime);
return returnvalue::OK;
} else {

View File

@ -6,10 +6,10 @@
class Service9TimeManagement : public PusServiceBase {
public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
//!< Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
static constexpr Event CLOCK_SET =
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET_FAILURE =
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;

View File

@ -31,9 +31,8 @@ LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
LocalPool::~LocalPool() = default;
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size,
bool ignoreFault) {
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
ReturnValue_t LocalPool::addData(store_address_t* storageId, const uint8_t* data, size_t size) {
ReturnValue_t status = reserveSpace(size, storageId);
if (status == returnvalue::OK) {
write(*storageId, data, size);
}
@ -49,8 +48,8 @@ ReturnValue_t LocalPool::getData(store_address_t packetId, const uint8_t** packe
}
ReturnValue_t LocalPool::getFreeElement(store_address_t* storageId, const size_t size,
uint8_t** pData, bool ignoreFault) {
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
uint8_t** pData) {
ReturnValue_t status = reserveSpace(size, storageId);
if (status == returnvalue::OK) {
*pData = &store[storageId->poolIndex][getRawPosition(*storageId)];
} else {
@ -167,7 +166,7 @@ void LocalPool::clearStore() {
}
}
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId, bool ignoreFault) {
ReturnValue_t LocalPool::reserveSpace(size_t size, store_address_t* storeId) {
ReturnValue_t status = getSubPoolIndex(size, &storeId->poolIndex);
if (status != returnvalue::OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
@ -318,27 +317,3 @@ bool LocalPool::hasDataAtId(store_address_t storeId) const {
}
return false;
}
ReturnValue_t LocalPool::getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) {
return StorageManagerIF::getFreeElement(storeId, size, pData);
}
ConstAccessorPair LocalPool::getData(store_address_t storeId) {
return StorageManagerIF::getData(storeId);
}
ReturnValue_t LocalPool::addData(store_address_t* storeId, const uint8_t* data, size_t size) {
return StorageManagerIF::addData(storeId, data, size);
}
ReturnValue_t LocalPool::getData(store_address_t storeId, ConstStorageAccessor& accessor) {
return StorageManagerIF::getData(storeId, accessor);
}
ReturnValue_t LocalPool::modifyData(store_address_t storeId, StorageAccessor& accessor) {
return StorageManagerIF::modifyData(storeId, accessor);
}
AccessorPair LocalPool::modifyData(store_address_t storeId) {
return StorageManagerIF::modifyData(storeId);
}

View File

@ -86,21 +86,13 @@ class LocalPool : public SystemObject, public StorageManagerIF {
/**
* Documentation: See StorageManagerIF.h
*/
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size,
bool ignoreFault) override;
ReturnValue_t addData(store_address_t* storeId, const uint8_t* data, size_t size) override;
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData) override;
ReturnValue_t getFreeElement(store_address_t* storeId, size_t size, uint8_t** pData,
bool ignoreFault) override;
ConstAccessorPair getData(store_address_t storeId) override;
ReturnValue_t getData(store_address_t storeId, ConstStorageAccessor& accessor) override;
ReturnValue_t getData(store_address_t storeId, const uint8_t** packet_ptr, size_t* size) override;
AccessorPair modifyData(store_address_t storeId) override;
ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr, size_t* size) override;
ReturnValue_t modifyData(store_address_t storeId, StorageAccessor& accessor) override;
ReturnValue_t deleteData(store_address_t storeId) override;
ReturnValue_t deleteData(uint8_t* ptr, size_t size, store_address_t* storeId) override;
@ -136,6 +128,12 @@ class LocalPool : public SystemObject, public StorageManagerIF {
[[nodiscard]] max_subpools_t getNumberOfSubPools() const override;
[[nodiscard]] bool hasDataAtId(store_address_t storeId) const override;
// Using functions provided by StorageManagerIF requires either a fully qualified path
// like for example localPool.StorageManagerIF::getFreeElement(...) or re-exporting
// the fully qualified path with the using directive.
using StorageManagerIF::getData;
using StorageManagerIF::modifyData;
protected:
/**
* With this helper method, a free element of @c size is reserved.
@ -144,7 +142,7 @@ class LocalPool : public SystemObject, public StorageManagerIF {
* @return - returnvalue::OK on success,
* - the return codes of #getPoolIndex or #findEmpty otherwise.
*/
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault);
virtual ReturnValue_t reserveSpace(size_t size, store_address_t* address);
private:
/**
@ -188,6 +186,8 @@ class LocalPool : public SystemObject, public StorageManagerIF {
std::vector<std::vector<size_type>> sizeLists =
std::vector<std::vector<size_type>>(NUMBER_OF_SUBPOOLS);
bool ignoreFault = false;
//! A variable to determine whether higher n pools are used if
//! the store is full.
bool spillsToHigherPools = false;

View File

@ -9,10 +9,9 @@ PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPo
PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); }
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address,
bool ignoreFault) {
ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) {
MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs);
ReturnValue_t status = LocalPool::reserveSpace(size, address, ignoreFault);
ReturnValue_t status = LocalPool::reserveSpace(size, address);
return status;
}

View File

@ -57,7 +57,7 @@ class PoolManager : public LocalPool {
//! Default mutex timeout value to prevent permanent blocking.
uint32_t mutexTimeoutMs = 20;
ReturnValue_t reserveSpace(size_t size, store_address_t* address, bool ignoreFault) override;
ReturnValue_t reserveSpace(size_t size, store_address_t* address) override;
/**
* @brief The mutex is created in the constructor and makes

View File

@ -55,7 +55,7 @@ class StorageManagerIF {
/**
* @brief This is the empty virtual destructor as required for C++ interfaces.
*/
~StorageManagerIF() = default;
virtual ~StorageManagerIF() = default;
/**
* @brief With addData, a free storage position is allocated and data
* stored there.
@ -66,12 +66,7 @@ class StorageManagerIF {
* @return Returns @returnvalue::OK if data was added.
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
*/
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size,
bool ignoreFault) = 0;
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) {
return addData(storageId, data, size, false);
}
virtual ReturnValue_t addData(store_address_t* storageId, const uint8_t* data, size_t size) = 0;
/**
* @brief With deleteData, the storageManager frees the memory region
@ -186,12 +181,8 @@ class StorageManagerIF {
* @return Returns @returnvalue::OK if data was added.
* @returnvalue::FAILED if data could not be added, storageId is unchanged then.
*/
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr,
bool ignoreFault) = 0;
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size, uint8_t** dataPtr) {
return getFreeElement(storageId, size, dataPtr, false);
}
virtual ReturnValue_t getFreeElement(store_address_t* storageId, size_t size,
uint8_t** dataPtr) = 0;
[[nodiscard]] virtual bool hasDataAtId(store_address_t storeId) const = 0;

View File

@ -91,11 +91,10 @@ void Subsystem::performChildOperation() {
}
if (currentSequenceIterator->getWaitSeconds() != 0) {
if (uptimeStartTable == 0) {
Clock::getUptime(&uptimeStartTable);
uptimeStartTable = Clock::getUptime_ms();
return;
} else {
uint32_t uptimeNow;
Clock::getUptime(&uptimeNow);
uint32_t uptimeNow = Clock::getUptime_ms();
if ((uptimeNow - uptimeStartTable) < (currentSequenceIterator->getWaitSeconds() * 1000)) {
return;
}

View File

@ -33,12 +33,8 @@ struct SequenceEntry : public TableSequenceBase {
};
/**
* @brief This class extends the SubsystemBase to perform the management of mode tables
* and mode sequences
* @brief TODO: documentation missing
* @details
* This class is able to use mode tables and sequences to command all its children into the
* right mode. Fallback sequences can be used to handle failed transitions or have a fallback
* in case a component can't keep its current mode.
*/
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
public:

View File

@ -8,13 +8,11 @@ SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t
uint16_t commandQueueDepth)
: SystemObject(setObjectId),
mode(initialMode),
commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
CommandMessage::MAX_MESSAGE_SIZE)),
healthHelper(this, setObjectId),
modeHelper(this),
parentId(parent) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
}
parentId(parent) {}
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
@ -33,9 +31,8 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
info.mode = MODE_OFF;
}
} else {
// intentional to force an initial command during system startup
info.commandQueue = child->getCommandQueue();
info.mode = HasModesIF::MODE_UNDEFINED;
info.mode = -1; // intentional to force an initial command during system startup
}
info.submode = SUBMODE_NONE;

View File

@ -15,14 +15,7 @@
/**
* @defgroup subsystems Subsystem Objects
* All Subsystem and Assemblies can derive from this class. It contains helper classes to
* perform mode and health handling, which allows OBSW developers to build a mode tree for
* the whole satellite.
*
* Aside from setting up a mode tree and being able to executing mode tables, this class does not
* provide an implementation on what to do with the features. To build a mode tree, helper classes
* like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base
* class.
* Contains all Subsystem and Assemblies
*/
class SubsystemBase : public SystemObject,
public HasModesIF,
@ -102,7 +95,6 @@ class SubsystemBase : public SystemObject,
Submode_t targetSubmode);
/**
* This function takes care of sending all according mode commands specified inside a mode table.
* We need to know the target Submode, as children are able to inherit the submode
* Still, we have a default for all child implementations which do not use submode inheritance
*/

View File

@ -4,13 +4,14 @@
AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid,
ThermalModuleIF *thermalModule)
: SystemObject(setObjectid), healthHelper(this, setObjectid), parameterHelper(this) {
if (thermalModule != nullptr) {
: SystemObject(setObjectid),
commandQueue(NULL),
healthHelper(this, setObjectid),
parameterHelper(this) {
if (thermalModule != NULL) {
thermalModule->registerSensor(this);
}
auto mqArgs = MqArgs(setObjectid, static_cast<void *>(this));
commandQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue();
}
AbstractTemperatureSensor::~AbstractTemperatureSensor() {

View File

@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF,
HasHealthIF::HealthState getHealth();
protected:
MessageQueueIF* commandQueue = nullptr;
MessageQueueIF* commandQueue;
HealthHelper healthHelper;
ParameterHelper parameterHelper;

View File

@ -12,9 +12,7 @@ Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1)
switch1(switch1),
heaterOnCountdown(10800000) /*about two orbits*/,
parameterHelper(this) {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
eventQueue = QueueFactory::instance()->createMessageQueue(
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
eventQueue = QueueFactory::instance()->createMessageQueue();
}
Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); }
@ -200,10 +198,9 @@ void Heater::setSwitch(uint8_t number, ReturnValue_t state, uint32_t* uptimeOfSw
} else {
if ((*uptimeOfSwitching == INVALID_UPTIME)) {
powerSwitcher->sendSwitchCommand(number, state);
Clock::getUptime(uptimeOfSwitching);
*uptimeOfSwitching = Clock::getUptime_ms();
} else {
uint32_t currentUptime;
Clock::getUptime(&currentUptime);
uint32_t currentUptime = Clock::getUptime_ms();
if (currentUptime - *uptimeOfSwitching > powerSwitcher->getSwitchDelayMs()) {
*uptimeOfSwitching = INVALID_UPTIME;
if (healthHelper.healthTable->isHealthy(getObjectId())) {

View File

@ -13,9 +13,9 @@ class ThermalComponentIF : public HasParametersIF {
static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW);
static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW);
static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW);
//!< Is thrown when a device should start-up, but the temperature is out
//!< of OP range. P1: thermalState of the component, P2: 0
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW);
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(
5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out
//!< of OP range. P1: thermalState of the component, P2: 0
static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF;
static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1);

View File

@ -552,10 +552,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short*
if (to == nullptr or from == nullptr) {
return returnvalue::FAILED;
}
uint16_t days = (from->dayMSB << 8) + from->dayLSB;
if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) {
return INVALID_TIME_FORMAT;
}
int32_t days = (from->dayMSB << 8) + from->dayLSB;
days -= DAYS_CCSDS_TO_UNIX_EPOCH;
to->tv_sec = days * SECONDS_PER_DAY;
uint32_t msDay =

View File

@ -14,8 +14,10 @@
#include <ctime>
#endif
class Clock {
public:
// https://xkcd.com/927/
typedef struct {
uint32_t year; //!< Year, A.D.
uint32_t month; //!< Month, 1 .. 12.
@ -26,14 +28,6 @@ class Clock {
uint32_t usecond; //!< Microseconds, 0 .. 999999
} TimeOfDay_t;
/**
* This method returns the number of clock ticks per second.
* In RTEMS, this is typically 1000.
* @return The number of ticks.
*
* @deprecated, we should not worry about ticks, but only time
*/
static uint32_t getTicksPerSecond();
/**
* This system call sets the system time.
* To set the time, it uses a TimeOfDay_t struct.
@ -61,13 +55,8 @@ class Clock {
/**
* Get the time since boot in a timeval struct
*
* @param[out] time A pointer to a timeval struct where the uptime is stored.
* @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned.
*
* @deprecated, I do not think this should be able to fail, use timeval getUptime()
* @return a timeval struct where the uptime is stored
*/
static ReturnValue_t getUptime(timeval *uptime);
static timeval getUptime();
/**
@ -79,7 +68,7 @@ class Clock {
* @param ms uptime in ms
* @return returnvalue::OK on success. Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getUptime(uint32_t *uptimeMs);
static uint32_t getUptime_ms();
/**
* Returns the time in microseconds since an OS-defined epoch.
@ -90,6 +79,7 @@ class Clock {
* - Otherwise, the OS failure code is returned.
*/
static ReturnValue_t getClock_usecs(uint64_t *time);
/**
* Returns the time in a TimeOfDay_t struct.
* @param time A pointer to a TimeOfDay_t struct.
@ -106,6 +96,7 @@ class Clock {
* @return
*/
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
/**
* Converts a time of day struct to POSIX seconds.
* @param time The time of day as input

View File

@ -1,4 +1,5 @@
#include <ctime>
#include <cstdlib>
#include "fsfw/ipc/MutexGuard.h"
#include "fsfw/timemanager/Clock.h"
@ -53,34 +54,74 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
}
ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
struct tm* timeInfo;
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s
// in the Windows CRT is incompatible with the C standard but this should not be an issue for
// this implementation
ReturnValue_t result = checkOrCreateClockMutex();
if (result != returnvalue::OK) {
return result;
}
// gmtime writes its output in a global buffer which is not Thread Safe
// Therefore we have to use a Mutex here
MutexGuard helper(timeMutex);
struct tm time_tm;
// WINDOWS does not provide gmtime_r, but gmtime_s
#ifdef PLATFORM_WIN
time_t time;
time = from->tv_sec;
timeInfo = gmtime(&time);
errno_t result = gmtime_s(&time_tm, &from->tv_sec);
if (result != 0) {
return returnvalue::FAILED;
}
#else
timeInfo = gmtime(&from->tv_sec);
void* result = gmtime_r(&from->tv_sec, &time_tm);
if (result == nullptr) {
return returnvalue::FAILED;
}
#endif
to->year = timeInfo->tm_year + 1900;
to->month = timeInfo->tm_mon + 1;
to->day = timeInfo->tm_mday;
to->hour = timeInfo->tm_hour;
to->minute = timeInfo->tm_min;
to->second = timeInfo->tm_sec;
to->year = time_tm.tm_year + 1900;
to->month = time_tm.tm_mon + 1;
to->day = time_tm.tm_mday;
to->hour = time_tm.tm_hour;
to->minute = time_tm.tm_min;
to->second = time_tm.tm_sec;
to->usecond = from->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_tm.tm_isdst = 0;
// Windows:
// time_t seconds = _mkgmtime(&time_tm);
// Glibc:
// time_t seconds = timegm(&time_tm);
// Portable (?)
char* tz;
tz = getenv("TZ");
setenv("TZ", "", 1);
tzset();
time_t seconds = mktime(&time_tm);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
to->tv_sec = seconds;
to->tv_usec = from->usecond;
if (seconds == (time_t) -1) {
return returnvalue::FAILED;
}
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;
}
ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == nullptr) {
MutexFactory* mutexFactory = MutexFactory::instance();
@ -94,3 +135,37 @@ ReturnValue_t Clock::checkOrCreateClockMutex() {
}
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;
}
return convertTimevalToTimeOfDay(&time_timeval, time);
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval timeVal{};
ReturnValue_t result = getClock_timeval(&timeVal);
if (result != returnvalue::OK) {
return result;
}
*time = static_cast<uint64_t>(timeVal.tv_sec) * 1e6 + timeVal.tv_usec;
return returnvalue::OK;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timeval timeTimeval{};
ReturnValue_t result = convertTimeOfDayToTimeval(time, &timeTimeval);
if (result != returnvalue::OK) {
return result;
}
return setClock(&timeTimeval);
}
uint32_t Clock::getUptime_ms() {
timeval uptime = getUptime();
// TODO verify that overflow is correct
return uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3;
}

View File

@ -1,19 +1,15 @@
#include "fsfw/timemanager/Countdown.h"
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
if (startImmediately) {
setTimeout(initialTimeout);
} else {
timeout = initialTimeout;
}
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
setTimeout(initialTimeout);
}
Countdown::~Countdown() {}
ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) {
ReturnValue_t returnValue = Clock::getUptime(&startTime);
startTime = Clock::getUptime_ms();
timeout = milliseconds;
return returnValue;
return returnvalue::OK;
}
bool Countdown::hasTimedOut() const {
@ -43,7 +39,5 @@ uint32_t Countdown::getRemainingMillis() const {
}
uint32_t Countdown::getCurrentTime() const {
uint32_t currentTime;
Clock::getUptime(&currentTime);
return currentTime;
return Clock::getUptime_ms();
}

View File

@ -26,9 +26,8 @@ class Countdown {
* Otherwise a call to hasTimedOut might return True.
*
* @param initialTimeout Countdown duration in milliseconds
* @param startImmediately Set to false if countdown should not be started immediately
*/
Countdown(uint32_t initialTimeout = 0, bool startImmediately = true);
Countdown(uint32_t initialTimeout = 0);
~Countdown();
/**
* Call to set a new countdown duration.

View File

@ -9,10 +9,10 @@
Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode)
: displayOnDestruction(displayOnDestruction), displayMode(displayMode) {
// Measures start time on initialization.
Clock::getUptime(&startTime);
startTime = Clock::getUptime();
}
void Stopwatch::start() { Clock::getUptime(&startTime); }
void Stopwatch::start() { startTime = Clock::getUptime(); }
dur_millis_t Stopwatch::stop(bool display) {
stopInternal();
@ -62,7 +62,6 @@ void Stopwatch::setDisplayMode(StopwatchDisplayMode displayMode) {
StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; }
void Stopwatch::stopInternal() {
timeval endTime;
Clock::getUptime(&endTime);
timeval endTime = Clock::getUptime();
elapsedTime = endTime - startTime;
}

View File

@ -1,7 +1,10 @@
#ifndef FSFW_TIMEMANAGER_TIMEREADERIF_H
#define FSFW_TIMEMANAGER_TIMEREADERIF_H
#include <cstdio>
#include <cstdlib>
#include <sys/time.h>
#include "fsfw/platform.h"

View File

@ -33,47 +33,50 @@ class TmStoreBackendIF : public HasParametersIF {
static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
//! Initiating sending data to store failed. Low, par1:
//! returnCode, par2: integer (debug info)
static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
//! Data was sent, but writing failed. Low, par1: returnCode, par2: 0
static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW);
//! Initiating reading data from store failed. Low, par1: returnCode, par2: 0
static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW);
//! Data was requested, but access failed. Low, par1: returnCode, par2: 0
static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW);
//! An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info)
static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW);
//! Storing data failed. May simply be a full store. Low, par1: returnCode,
//! par2: integer (sequence count of failed packet).
static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW);
//! Dumping retrieved data failed. Low, par1: returnCode,
//! par2: integer (sequence count of failed packet).
static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW);
//! Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
//! Store was not initialized. Starts empty. Info, parameters both zero.
static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW);
//! Data was read out, but it is inconsistent. Low par1:
//! Memory address of corruption, par2: integer (debug info)
static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO);
static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW);
//! Info event indicating the store will be initialized, either at boot or after IOB switch.
//! Info. pars: 0
static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO);
//! Info event indicating the store was successfully initialized, either at boot or after
//! IOB switch. Info. pars: 0
static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO);
//! Info event indicating that dumping finished successfully.
//! par1: Number of dumped packets. par2: APID/SSC (16bits each)
static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO);
//! Info event indicating that deletion finished successfully.
//! par1:Number of deleted packets. par2: APID/SSC (16bits each)
static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO);
//! Info event indicating that something went wrong during deletion. pars: 0
static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW);
//! Info that the a auto catalog report failed
static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);
static const Event STORE_SEND_WRITE_FAILED =
MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1:
//!< returnCode, par2: integer (debug info)
static const Event STORE_WRITE_FAILED = MAKE_EVENT(
1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
static const Event STORE_SEND_READ_FAILED =
MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1:
//!< returnCode, par2: 0
static const Event STORE_READ_FAILED = MAKE_EVENT(
3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
static const Event UNEXPECTED_MSG =
MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low,
//!< par1: 0, par2: integer (debug info)
static const Event STORING_FAILED = MAKE_EVENT(
5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1:
//!< returnCode, par2: integer (sequence count of failed packet).
static const Event TM_DUMP_FAILED =
MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode,
//!< par2: integer (sequence count of failed packet).
static const Event STORE_INIT_FAILED =
MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode,
//!< par2: integer (debug info)
static const Event STORE_INIT_EMPTY = MAKE_EVENT(
8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
static const Event STORE_CONTENT_CORRUPTED =
MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1:
//!< Memory address of corruption, par2: integer (debug info)
static const Event STORE_INITIALIZE =
MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized,
//!< either at boot or after IOB switch. Info. pars: 0
static const Event INIT_DONE = MAKE_EVENT(
11, severity::INFO); //!< Info event indicating the store was successfully initialized,
//!< either at boot or after IOB switch. Info. pars: 0
static const Event DUMP_FINISHED = MAKE_EVENT(
12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1:
//!< Number of dumped packets. par2: APID/SSC (16bits each)
static const Event DELETION_FINISHED = MAKE_EVENT(
13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1:
//!< Number of deleted packets. par2: APID/SSC (16bits each)
static const Event DELETION_FAILED = MAKE_EVENT(
14,
severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0
static const Event AUTO_CATALOGS_SENDING_FAILED =
MAKE_EVENT(15, severity::INFO); //!< Info that the a auto catalog report failed
virtual ~TmStoreBackendIF() {}

View File

@ -21,7 +21,7 @@ SpacePacketReader::~SpacePacketReader() = default;
inline uint16_t SpacePacketReader::getPacketIdRaw() const { return ccsds::getPacketId(*spHeader); }
const uint8_t* SpacePacketReader::getPacketData() { return packetDataField; }
const uint8_t* SpacePacketReader::getPacketData() const { return packetDataField; }
ReturnValue_t SpacePacketReader::setData(uint8_t* data, size_t maxSize_, void* args) {
return setInternalFields(data, maxSize_);

View File

@ -71,7 +71,7 @@ class SpacePacketReader : public SpacePacketIF,
// Helper methods:
[[nodiscard]] ReturnValue_t checkSize() const;
const uint8_t* getPacketData();
const uint8_t* getPacketData() const;
ReturnValue_t setReadOnlyData(const uint8_t* data, size_t maxSize);

View File

@ -27,10 +27,8 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a
verificationReporter(verificationReporter),
commandMap(numberOfParallelCommands),
name(name) {
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE;
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
}
void CommandingServiceBase::setPacketSource(object_id_t packetSource_) {
@ -225,7 +223,7 @@ void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, Comma
// In case a new command is to be sent immediately, this is performed here.
// If no new command is sent, only analyse reply result by initializing
// sendResult as returnvalue::OK
// sendResult as RETURN_OK
ReturnValue_t sendResult = returnvalue::OK;
if (nextCommand->getCommand() != CommandMessage::CMD_NONE) {
sendResult = commandQueue->sendMessage(reply->getSender(), nextCommand);
@ -350,7 +348,7 @@ void CommandingServiceBase::startExecution(store_address_t storeId, CommandMapIt
sendResult = commandQueue->sendMessage(iter.value->first, &command);
}
if (sendResult == returnvalue::OK) {
Clock::getUptime(&iter->second.uptimeOfStart);
iter->second.uptimeOfStart = Clock::getUptime_ms();
iter->second.step = 0;
iter->second.subservice = tcReader.getSubService();
iter->second.command = command.getCommand();
@ -436,8 +434,7 @@ inline void CommandingServiceBase::doPeriodicOperation() {}
MessageQueueId_t CommandingServiceBase::getCommandQueue() { return commandQueue->getId(); }
void CommandingServiceBase::checkTimeout() {
uint32_t uptime;
Clock::getUptime(&uptime);
uint32_t uptime = Clock::getUptime_ms();
CommandMapIter iter;
for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) {
if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {

View File

@ -11,7 +11,7 @@ class SourceSequenceCounter {
SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {}
void increment() { sequenceCount = (sequenceCount + 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
void decrement() { sequenceCount = (sequenceCount - 1) % (ccsds::LIMIT_SEQUENCE_COUNT); }
uint16_t get() { return this->sequenceCount; }
uint16_t get() const { return this->sequenceCount; }
void reset(uint16_t toValue = 0) { sequenceCount = toValue % (ccsds::LIMIT_SEQUENCE_COUNT); }
SourceSequenceCounter& operator++(int) {
this->increment();

View File

@ -16,9 +16,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
tcDestination(tcDestination)
{
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
}
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
@ -37,7 +35,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
}
}
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) {
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
return returnvalue::OK;
@ -173,18 +171,15 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
}
if (tmFifo->full()) {
if (warningSwitch) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!"
<< std::endl;
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!"
<< std::endl;
#else
sif::printWarning(
"TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!\n");
sif::printWarning(
"TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!\n");
#endif
warningSwitch = true;
}
if (overwriteOld) {
tmFifo->retrieve(&storeId);
tmStore->deleteData(storeId);

Some files were not shown because too many files have changed in this diff Show More