Compare commits

..

21 Commits

Author SHA1 Message Date
7426e10f82 clocks suck a little less
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
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
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
2023-01-20 16:05:04 +01:00
e6af6200ae updating CI
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
2023-01-19 17:32:23 +01:00
5ca3e83934 working on rtems CI build
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
2023-01-19 16:46:43 +01:00
6adabb059a fixing rtems cmake config
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
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
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
2023-01-19 14:24:33 +01:00
fdfdce2fb0 compiling, crashing when run
All checks were successful
fsfw/fsfw/pipeline/head This commit looks good
2023-01-18 00:25:25 +01:00
90efb132d0 fixing rebase error
Some checks failed
fsfw/fsfw/pipeline/pr-development There was a failure building this commit
fsfw/fsfw/pipeline/head This commit looks good
2023-01-16 12:41:23 +01:00
fe9804d922 format
Some checks failed
fsfw/fsfw/pipeline/head There was a failure building this commit
2023-01-16 12:35:14 +01:00
a0eae66c35 checking if this helps docker build
Some checks failed
fsfw/fsfw/pipeline/head There was a failure building this commit
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
67 changed files with 792 additions and 1172 deletions

View File

@ -8,38 +8,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
# [v6.0.0] 2023-02-10 # [v6.0.0]
## Fixes ## Fixes
- Mode Service: Add allowed subservice
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/739
- `CService200ModeManagement`: Various bugfixes which lead to now execution complete being generated
on mode announcements, duplicate mode reply generated on announce commands, and the mode read
subservice not working properly.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/736
- Memory leak fixes for the TCP/IP TMTC bridge.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/737
- `Service9TimeManagement`: Fix the time dump at the `SET_TIME` subservice: Include clock timeval
seconds instead of uptime.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/726
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
only the X scaling factor was used.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
- HAL MGM3100 Handler: Z value was previously calculated with bytes of the X value.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/733
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
to false correctly because the `read` and `write` calls were missing.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/728
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
of the correct unsegmented flags (0b11) as specified in the standard.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/727
- TC Scheduler Service 11: Add size and CRC check for contained TC. - TC Scheduler Service 11: Add size and CRC check for contained TC.
Bug: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/issues/719
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/720
- Only delete health table entry in `HealthHelper` destructor if - Only delete health table entry in `HealthHelper` destructor if
health table was set. health table was set.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/710/files
- I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator. - I2C Bugfixes: Do not keep iterator as member and fix some incorrect handling with the iterator.
Also properly reset the reply size for successfull transfers and erroneous transfers. Also properly reset the reply size for successfull transfers and erroneous transfers.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/700
@ -49,82 +25,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `TcpTmTcServer.cpp`: The server was actually not able to handle - `TcpTmTcServer.cpp`: The server was actually not able to handle
CCSDS packets which were clumped together. This has been fixed now. CCSDS packets which were clumped together. This has been fixed now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/673
- `CServiceHealthCommanding`: Add announce all health info implementation
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- various fixes related to linux Unittests and memory leaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/715
- small fix to allow teardown handling
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/713
- fix compiler warning for fixed array list copy ctor
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/704
- missing include
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/703
- defaultconfig did not build anymore
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/702
- hotfix
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/699
- small fix for helper
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/698
- missing retval conv
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/697
- DHB Countdown Bug
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/693
- doc corrections
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/687
- better error printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/686
- include correction
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/683
- better warning for missing include paths
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/676
- Service 11 regression
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/670
## Added ## Added
- Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
option on the TCP server. CTOR prototype has changed and expects an explicit
TCP configuration struct to be passed.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
- `DleParser` helper class to parse DLE encoded packets from a byte stream. - `DleParser` helper class to parse DLE encoded packets from a byte stream.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
- `UioMapper` is able to resolve symlinks now. - `UioMapper` is able to resolve symlinks now.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/709
- Add new `UnsignedByteField` class - Add new `UnsignedByteField` class
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/660
- publish documentation for development and master branch
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/681
- Add Linux HAL options
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/663
- Expand SerializeIF
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/656
- PUS Service 11: Additional Safety Check
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/666
- improvements for auto-formatter script
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/665
- provide a weak print char impl
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/674
## Removed
- now that doc server is up, remove markdown files
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/688
- remove bsp specific code
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/679
## Changes ## Changes
- `CService201HealthCommanding` renamed to `CServiceHealthCommanding`,
service ID customizable now. `CServiceHealthCommanding` expects configuration struct
`HealthServiceCfg` now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/725
- `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now - `AcceptsTelemetryIF`: `getReportReceptionQueue` is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/712
- Moved some container returnvalues to dedicated header and namespace - Moved some container returnvalues to dedicated header and namespace
so they can be used without template specification. to they can be used without template specification.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/707
- Remove default secondary header argument for - Remove default secondary header argument for
`uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and `uint16_t getTcSpacePacketIdFromApid(uint16_t apid, bool secondaryHeaderFlag)` and
@ -154,41 +70,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects - `DeviceHandlerBase`: New signature of `handleDeviceTm` which expects
a `const SerializeIF&` and additional helper variant which expects `const uint8_t*` a `const SerializeIF&` and additional helper variant which expects `const uint8_t*`
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/671
- Move some generic `StorageManagerIF` implementations from `LocalPool` to
interface itself so it can be re-used more easily. Also add new
abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`: - Improvements for `AcceptsTelemetryIF` and `AcceptsTelecommandsIF`:
- Make functions `const` where it makes sense - Make functions `const` where it makes sense
- Add `const char* getName const` abstract function - Add `const char* getName const` abstract function
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/684
- Generic TMTC Bridge Update - Move some generic `StorageManagerIF` implementations from `LocalPool` to
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/734 interface itself so it can be re-used more easily. Also add new
- comment tweak to event parser can read everything abstract function `bool hasDataAtId(store_address_t storeId) const`.
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/732 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/685
- CMakeLists file updates
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/731
- improve srv20 error messages
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/723
- I2C Linux: remove duplicate printout
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/718
- printout handling improvements
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/717
- vec getter, reset for content
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/716
- updates for source sequence counter
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/714
- SP reader getPacketData is const now
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/708
- refactoring of serial drivers for linux
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/705
- Local Pool Update Remove Add Data Ignore Fault Argument
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/701
- Switch to new documentation server
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/694
- Windows Tweaks
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/691
- Refactor Local Pool API
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/667
- group MGM data in local pool vectors
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/664
## CFDP ## CFDP
@ -208,7 +101,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
implementation without an extra component implementation without an extra component
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682 PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/682
# [v5.0.0] 2022-07-25 # [v5.0.0] 25.07.2022
## Changes ## Changes

View File

@ -13,7 +13,7 @@ list(APPEND CMAKE_MODULE_PATH
# Version file handling # # Version file handling #
# ############################################################################## # ##############################################################################
set(FSFW_VERSION_IF_GIT_FAILS 6) set(FSFW_VERSION_IF_GIT_FAILS 5)
set(FSFW_SUBVERSION_IF_GIT_FAILS 0) set(FSFW_SUBVERSION_IF_GIT_FAILS 0)
set(FSFW_REVISION_IF_GIT_FAILS 0) set(FSFW_REVISION_IF_GIT_FAILS 0)
@ -158,7 +158,7 @@ if(FSFW_BUILD_TESTS)
if(NOT Catch2_FOUND) if(NOT Catch2_FOUND)
message( message(
STATUS STATUS
"${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent." "${MSG_PREFIX} Catch2 installation not found. Downloading Catch2 library with FetchContent"
) )
include(FetchContent) include(FetchContent)
@ -174,6 +174,27 @@ if(FSFW_BUILD_TESTS)
configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h) configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h)
configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h) configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h)
if(FSFW_OSAL MATCHES "freertos")
message(STATUS "${MSG_PREFIX} Downloading FreeRTOS with FetchContent")
include(FetchContent)
set(FreeRTOS_PORT posix)
FetchContent_Declare(
FreeRTOS
GIT_REPOSITORY https://egit.irs.uni-stuttgart.de/fsfw/FreeRTOS-LTS
GIT_TAG develop
GIT_SUBMODULES FreeRTOS/FreeRTOS-Kernel)
FetchContent_MakeAvailable(FreeRTOS)
set(LIB_OS_NAME FreeRTOS)
target_include_directories(FreeRTOS PUBLIC unittests/testcfg/freertos)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(FreeRTOS PRIVATE ${CMAKE_THREAD_LIBS_INIT})
endif()
project(${FSFW_TEST_TGT} CXX C) project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT}) add_executable(${FSFW_TEST_TGT})
if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) if(IPO_SUPPORTED AND FSFW_ENABLE_IPO)
@ -201,8 +222,8 @@ find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
message( message(
STATUS STATUS
"${MSG_PREFIX} ETL installation not found. Downloading ETL with FetchContent." "${MSG_PREFIX} No ETL installation was found with find_package. Installing and providing "
) "etl with FindPackage")
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
@ -226,6 +247,7 @@ if(FSFW_FETCH_CONTENT_TARGETS)
# GitHub issue: https://github.com/catchorg/Catch2/issues/2417 # GitHub issue: https://github.com/catchorg/Catch2/issues/2417
set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "") set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "")
endif() endif()
endif() endif()
set(FSFW_CORE_INC_PATH "inc") set(FSFW_CORE_INC_PATH "inc")
@ -360,6 +382,9 @@ if(FSFW_BUILD_TESTS)
endif() endif()
target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2
${LIB_FSFW_NAME}) ${LIB_FSFW_NAME})
if(FSFW_OSAL MATCHES "freertos")
target_link_libraries(${FSFW_TEST_TGT} PRIVATE FreeRTOS)
endif()
endif() endif()
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If # The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If

View File

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

105
automation/Jenkinsfile vendored
View File

@ -2,86 +2,61 @@ pipeline {
environment { environment {
BUILDDIR_HOST = 'cmake-build-tests-host' BUILDDIR_HOST = 'cmake-build-tests-host'
BUILDDIR_LINUX = 'cmake-build-tests-linux' BUILDDIR_LINUX = 'cmake-build-tests-linux'
BUILDDIR_FREERTOS = 'cmake-build-tests-freertos'
BUILDDIR_RTEMS = 'cmake-build-tests-rtems'
DOCDDIR = 'cmake-build-documentation' DOCDDIR = 'cmake-build-documentation'
} }
agent { agent {
docker { docker {
image 'fsfw-ci:d6' image 'fsfw-ci:d7'
args '--network host --sysctl fs.mqueue.msg_max=100' args '--network host --sysctl fs.mqueue.msg_max=100'
} }
} }
stages { stages {
stage('Host') { stage('Host') {
stages{ steps {
stage('Clean') { sh 'rm -rf $BUILDDIR_HOST'
steps {
sh 'rm -rf $BUILDDIR_HOST' dir(BUILDDIR_HOST) {
} sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
} sh 'cmake --build . -j4'
stage('Configure') { sh 'cmake --build . -- fsfw-tests_coverage -j4'
steps { sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
dir(BUILDDIR_HOST) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
}
}
}
stage('Build') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -j4'
}
}
}
stage('Unittests') {
steps {
dir(BUILDDIR_HOST) {
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_HOST) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
} }
} }
} }
stage('Linux') { stage('Linux') {
stages{ steps {
stage('Clean') { sh 'rm -rf $BUILDDIR_LINUX'
steps {
sh 'rm -rf $BUILDDIR_LINUX' dir(BUILDDIR_LINUX) {
} sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
sh 'cmake --build . -j4'
sh 'cmake --build . -- fsfw-tests_coverage -j4'
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
} }
stage('Configure') { }
steps { }
dir(BUILDDIR_LINUX) { stage('FreeRTOS') {
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' steps {
} sh 'rm -rf $BUILDDIR_FREERTOS'
}
dir(BUILDDIR_FREERTOS) {
sh 'cmake -DFSFW_OSAL=freertos -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
sh 'cmake --build . -j4'
sh 'cmake --build . -- fsfw-tests_coverage -j4'
//sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
} }
stage('Build') { }
steps { }
dir(BUILDDIR_LINUX) { stage('rtems') {
sh 'cmake --build . -j4' steps {
} sh 'rm -rf $BUILDDIR_RTEMS'
}
} dir(BUILDDIR_RTEMS) {
stage('Unittests') { sh 'cmake -DFSFW_OSAL=rtems -DFSFW_BUILD_TESTS=ON -DFSFW_TESTS_GEN_COV=OFF -DFSFW_CICD_BUILD=ON -DCMAKE_TOOLCHAIN_FILE=../unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake ..'
steps { sh 'cmake --build . -j4'
dir(BUILDDIR_LINUX) { sh 'qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio -semihosting -machine virt,gic-version=3 -cpu cortex-a72 -m 4000 -kernel fsfw-tests'
sh 'cmake --build . -- fsfw-tests_coverage -j4'
}
}
}
stage('Valgrind') {
steps {
dir(BUILDDIR_LINUX) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
}
}
} }
} }
} }

View File

@ -1,110 +0,0 @@
#! /bin/python
import argparse
import json
import urllib.request
import re
from pathlib import Path
def main() -> None:
parser = argparse.ArgumentParser(
description="List undocumented PRs"
)
parser.add_argument("-v", "--version", type=str, required=True)
args = parser.parse_args()
match = re.search("([0-9]+\.[0-9]+\.[0-9]+)", args.version)
if not match:
print("invalid version")
exit(1)
version = "v" + match.group(1)
print("looking for milestone for " + version + " ...")
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/milestones?name=" + version) as milestone_json:
milestones = json.load(milestone_json)
if (len(milestones) == 0):
print("did not find any milestone")
exit(1)
if (len(milestones) > 1):
print("found multiple milestons")
milestone_title = milestones[0]['title']
milestone = str(milestones[0]['id'])
print("Using Milestone \""+ milestone_title + "\" with id " + milestone)
milestone_prs = []
page = 1
last_count = 1;
while last_count != 0:
with urllib.request.urlopen("https://egit.irs.uni-stuttgart.de/api/v1/repos/fsfw/fsfw/pulls?state=closed&milestone=" + str(milestone) + "&limit=100&page=" + str(page)) as pull_requests_json:
pull_requests = json.load(pull_requests_json)
for pr in pull_requests:
milestone_prs.append({'number': str(pr['number']), 'title' : pr['title']})
page += 1
last_count = len(pull_requests)
print("Found " + str(len(milestone_prs)) + " closed PRs in Milestone")
print("looking for CHANGELOG.md ...")
path = Path(".")
files = list(path.glob("CHANGELOG.md"))
if (len(files) != 1):
files = list(path.glob("../CHANGELOG.md"))
if (len(files) != 1):
print("did not find CHANGELOG.md. Run script in either root directory or scripts subfolder.")
exit(1)
print("Scanning CHANGELOG.md ...")
changelog_prs = []
with open(files[0]) as changelog:
line = changelog.readline()
while (line):
#print("line: " + line)
match = re.search("\#.+(v[0-9]+\.[0-9]+\.[0-9]+)", line)
if (match):
if match.group(1) == version:
#print("found version")
line = changelog.readline()
continue
else:
#print("done with " + match.group(1))
break
match = re.search("PR: https://egit\.irs\.uni-stuttgart\.de/fsfw/fsfw/pulls/([0-9]+)", line)
if match:
changelog_prs.append(match.group(1))
line = changelog.readline()
print("Found " + str(len(changelog_prs)) + " PRs in CHANGELOG.md")
print("")
copy_array = changelog_prs.copy()
print("PRs in CHANGELOG.md that are not in Milestone:")
for pr in milestone_prs:
if pr['number'] in copy_array:
copy_array.remove(pr['number'])
for pr in copy_array:
print("https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr)
print("")
print("PRs in milestone that are not in CHANGELOG.md:")
for pr in milestone_prs:
if pr['number'] not in changelog_prs:
print("- " + pr['title'] + "\n PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/" + pr['number'])
main()

View File

@ -1,6 +1,5 @@
#include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h"
#include "fsfw/datapool/PoolReadGuard.h"
#include "fsfw/datapoollocal/LocalPoolVariable.h" #include "fsfw/datapoollocal/LocalPoolVariable.h"
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h" #include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
#include "fsfw/devicehandlers/DeviceTmReportingWrapper.h" #include "fsfw/devicehandlers/DeviceTmReportingWrapper.h"
@ -322,8 +321,7 @@ void DeviceHandlerBase::doStateMachine() {
if (mode != currentMode) { if (mode != currentMode) {
break; break;
} }
uint32_t currentUptime; uint32_t currentUptime = Clock::getUptime_ms();
Clock::getUptime(&currentUptime);
if (currentUptime - timeoutStart >= childTransitionDelay) { if (currentUptime - timeoutStart >= childTransitionDelay) {
#if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0 #if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0
char printout[60]; char printout[60];
@ -347,8 +345,7 @@ void DeviceHandlerBase::doStateMachine() {
setMode(_MODE_WAIT_ON); setMode(_MODE_WAIT_ON);
break; break;
case _MODE_WAIT_ON: { case _MODE_WAIT_ON: {
uint32_t currentUptime; uint32_t currentUptime = Clock::getUptime_ms();
Clock::getUptime(&currentUptime);
if (powerSwitcher != nullptr and if (powerSwitcher != nullptr and
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0); triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
@ -367,8 +364,7 @@ void DeviceHandlerBase::doStateMachine() {
} }
} break; } break;
case _MODE_WAIT_OFF: { case _MODE_WAIT_OFF: {
uint32_t currentUptime; uint32_t currentUptime = Clock::getUptime_ms();
Clock::getUptime(&currentUptime);
if (powerSwitcher == nullptr) { if (powerSwitcher == nullptr) {
setMode(MODE_OFF); setMode(MODE_OFF);
@ -578,7 +574,7 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
modeHelper.modeChanged(newMode, newSubmode); modeHelper.modeChanged(newMode, newSubmode);
announceMode(false); announceMode(false);
} }
Clock::getUptime(&timeoutStart); timeoutStart = Clock::getUptime_ms();
if (mode == MODE_OFF and thermalSet != nullptr) { if (mode == MODE_OFF and thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read(); ReturnValue_t result = thermalSet->read();
@ -1509,10 +1505,7 @@ DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() { void DeviceHandlerBase::setNormalDatapoolEntriesInvalid() {
for (const auto& reply : deviceReplyMap) { for (const auto& reply : deviceReplyMap) {
if (reply.second.dataSet != nullptr) { if (reply.second.dataSet != nullptr) {
PoolReadGuard pg(reply.second.dataSet); reply.second.dataSet->setValidity(false, true);
if (pg.getReadResult() == returnvalue::OK) {
reply.second.dataSet->setValidity(false, true);
}
} }
} }
} }

View File

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

View File

@ -8,8 +8,6 @@
#include "HealthTableIF.h" #include "HealthTableIF.h"
class HealthTable : public HealthTableIF, public SystemObject { class HealthTable : public HealthTableIF, public SystemObject {
friend class CServiceHealthCommanding;
public: public:
explicit HealthTable(object_id_t objectid); explicit HealthTable(object_id_t objectid);
~HealthTable() override; ~HealthTable() override;

View File

@ -7,10 +7,10 @@
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth) InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth)
: SystemObject(setObjectId), : SystemObject(setObjectId),
commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue), poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) { internalErrorDataset(this) {
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }

View File

@ -24,19 +24,3 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason
message->setParameter(reason); message->setParameter(reason);
message->setParameter2(0); message->setParameter2(0);
} }
void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) {
Command_t cmd;
if (recursive) {
cmd = CMD_MODE_ANNOUNCE_RECURSIVELY;
} else {
cmd = CMD_MODE_ANNOUNCE;
}
message.setCommand(cmd);
}
void ModeMessage::setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode) {
setModeMessage(&message, CMD_MODE_COMMAND, mode, submode);
}
void ModeMessage::setModeReadMessage(CommandMessage& message) { message.setCommand(CMD_MODE_READ); }

View File

@ -45,9 +45,6 @@ class ModeMessage {
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode, static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
Submode_t submode); Submode_t submode);
static void setCmdModeMessage(CommandMessage& message, Mode_t mode, Submode_t submode);
static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
static void setModeReadMessage(CommandMessage& message);
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason); static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
static void clear(CommandMessage* message); static void clear(CommandMessage* message);
}; };

View File

@ -18,10 +18,7 @@ elseif(FSFW_OSAL MATCHES "host")
endif() endif()
set(FSFW_OSAL_HOST 1) set(FSFW_OSAL_HOST 1)
else() else()
message( message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
WARNING
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
# Not set. Assumuing this is a host build, try to determine host OS # Not set. Assumuing this is a host build, try to determine host OS
if(WIN32) if(WIN32)
add_subdirectory(host) add_subdirectory(host)

View File

@ -26,12 +26,12 @@
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize, size_t receptionBufferSize, size_t ringBufferSize,
size_t ringBufferSize, ReceptionModes receptionMode) std::string customTcpServerPort, ReceptionModes receptionMode)
: SystemObject(objectId), : SystemObject(objectId),
tmtcBridgeId(tmtcTcpBridge), tmtcBridgeId(tmtcTcpBridge),
receptionMode(receptionMode), receptionMode(receptionMode),
tcpConfig(cfg), tcpConfig(std::move(customTcpServerPort)),
receptionBuffer(receptionBufferSize), receptionBuffer(receptionBufferSize),
ringBuffer(ringBufferSize, true) {} ringBuffer(ringBufferSize, true) {}
@ -91,15 +91,6 @@ ReturnValue_t TcpTmTcServer::initialize() {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
if (tcpConfig.reuseAddr) {
unsigned int enable = 1;
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
}
if (tcpConfig.reusePort) {
unsigned int enable = 1;
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
}
// Bind to the address found by getaddrinfo // Bind to the address found by getaddrinfo
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen)); retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
if (retval == SOCKET_ERROR) { if (retval == SOCKET_ERROR) {

View File

@ -41,11 +41,11 @@ class SpacePacketParser;
*/ */
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF { class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
public: public:
enum class ReceptionModes { SPACE_PACKETS };
struct TcpConfig { struct TcpConfig {
public: public:
TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {} explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort)
: tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {}
/** /**
* Passed to the recv call * Passed to the recv call
@ -63,23 +63,8 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
*/ */
int tcpTmFlags = 0; int tcpTmFlags = 0;
std::string tcpPort = DEFAULT_SERVER_PORT; const std::string tcpPort;
/**
* Sets the SO_REUSEADDR option on the socket. See
* https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is
* especially useful in a debugging and development environment where an OBSW image might be
* re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP
* port.
*/
bool reuseAddr = false;
/**
* Sets the SO_REUSEPORT option on the socket. See
* https://man7.org/linux/man-pages/man7/socket.7.html for more details.
*/
bool reusePort = false;
}; };
enum class ReceptionModes { SPACE_PACKETS };
static const std::string DEFAULT_SERVER_PORT; static const std::string DEFAULT_SERVER_PORT;
@ -95,9 +80,10 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
* size will be the Ethernet MTU size * size will be the Ethernet MTU size
* @param customTcpServerPort The user can specify another port than the default (7301) here. * @param customTcpServerPort The user can specify another port than the default (7301) here.
*/ */
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg, TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
size_t receptionBufferSize = RING_BUFFER_SIZE, size_t receptionBufferSize = RING_BUFFER_SIZE,
size_t ringBufferSize = RING_BUFFER_SIZE, size_t ringBufferSize = RING_BUFFER_SIZE,
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS); ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
~TcpTmTcServer() override; ~TcpTmTcServer() override;

View File

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

View File

@ -51,7 +51,7 @@ class BinarySemaphore : public SemaphoreIF {
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override; uint32_t timeoutMs = 0) override;
/** /**
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.

View File

@ -11,19 +11,6 @@
// TODO sanitize input? // TODO sanitize input?
// TODO much of this code can be reused for tick-only systems // TODO much of this code can be reused for tick-only systems
uint32_t Clock::getTicksPerSecond(void) { return 1000; }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
if (result != returnvalue::OK) {
return result;
}
return setClock(&time_timeval);
}
ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::setClock(const timeval* time) {
timeval uptime = getUptime(); timeval uptime = getUptime();
@ -44,81 +31,15 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return returnvalue::OK;
}
timeval Clock::getUptime() { timeval Clock::getUptime() {
TickType_t ticksSinceStart = xTaskGetTickCount(); TickType_t ticksSinceStart = xTaskGetTickCount();
return Timekeeper::ticksToTimeval(ticksSinceStart); return Timekeeper::ticksToTimeval(ticksSinceStart);
} }
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return returnvalue::OK;
}
// uint32_t Clock::getUptimeSeconds() { // uint32_t Clock::getUptimeSeconds() {
// timeval uptime = getUptime(); // timeval uptime = getUptime();
// return uptime.tv_sec; // return uptime.tv_sec;
// } // }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != returnvalue::OK) {
return result;
}
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
return returnvalue::OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != returnvalue::OK) {
return result;
}
struct tm time_tm;
gmtime_r(&time_timeval.tv_sec, &time_tm);
time->year = time_tm.tm_year + 1900;
time->month = time_tm.tm_mon + 1;
time->day = time_tm.tm_mday;
time->hour = time_tm.tm_hour;
time->minute = time_tm.tm_min;
time->second = time_tm.tm_sec;
time->usecond = time_timeval.tv_usec;
return returnvalue::OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) {
struct tm time_tm = {};
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
// Fails in 2038..
return returnvalue::OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. / 3600.;
return returnvalue::OK;
}

View File

@ -34,7 +34,7 @@ class CountingSemaphoreUsingTask : public SemaphoreIF {
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/ */
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override; uint32_t timeoutMs = 0) override;
/** /**
* Release a semaphore, increasing the number of available counting * Release a semaphore, increasing the number of available counting

View File

@ -56,7 +56,9 @@ ReturnValue_t FixedTimeslotTask::startTask() {
// start time for the first entry. // start time for the first entry.
auto slotListIter = pollingSeqTable.current; auto slotListIter = pollingSeqTable.current;
pollingSeqTable.intializeSequenceAfterTaskCreation(); ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation();
// Ignore returnvalue for now
static_cast<void>(result);
// The start time for the first entry is read. // The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs; uint32_t intervalMs = slotListIter->pollingTimeMs;

View File

@ -22,7 +22,7 @@ ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
return MutexIF::MUTEX_NOT_FOUND; return MutexIF::MUTEX_NOT_FOUND;
} }
// If the timeout type is BLOCKING, this will be the correct value. // If the timeout type is BLOCKING, this will be the correct value.
uint32_t timeout = portMAX_DELAY; TickType_t timeout = portMAX_DELAY;
if (timeoutType == TimeoutType::POLLING) { if (timeoutType == TimeoutType::POLLING) {
timeout = 0; timeout = 0;
} else if (timeoutType == TimeoutType::WAITING) { } else if (timeoutType == TimeoutType::WAITING) {

View File

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

View File

@ -11,7 +11,7 @@
* Architecture dependant portmacro.h function call. * Architecture dependant portmacro.h function call.
* Should be implemented in bsp. * Should be implemented in bsp.
*/ */
extern "C" void vRequestContextSwitchFromISR(); // extern "C" void vRequestContextSwitchFromISR();
/*! /*!
* Used by functions to tell if they are being called from * Used by functions to tell if they are being called from
@ -53,7 +53,7 @@ TaskHandle_t getCurrentTaskHandle();
* @return Smallest value of stack remaining since the task was started in * @return Smallest value of stack remaining since the task was started in
* words. * words.
*/ */
size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); // size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr);
}; // namespace TaskManagement }; // namespace TaskManagement

View File

@ -15,27 +15,6 @@
using SystemClock = std::chrono::system_clock; 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) { 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 /* 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. */ 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; time->tv_usec = timeUnix.tv_nsec / 1000.0;
return returnvalue::OK; return returnvalue::OK;
#else #else
#warning Clock::getClock_timeval() not implemented for your platform
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
#else #else
@ -75,15 +55,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
#endif #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 Clock::getUptime() {
timeval timeval; timeval timeval;
#if defined(PLATFORM_WIN) #if defined(PLATFORM_WIN)
@ -100,6 +71,7 @@ timeval Clock::getUptime() {
timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6); timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6);
} }
#else #else
#warning Clock::getUptime() not implemented for your platform
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif #endif
@ -107,66 +79,3 @@ timeval Clock::getUptime() {
return timeval; 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/ipc/MutexGuard.h"
#include "fsfw/serviceinterface/ServiceInterface.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) { ReturnValue_t Clock::setClock(const timeval* time) {
timespec timeUnix{}; timespec timeUnix{};
timeUnix.tv_sec = time->tv_sec; timeUnix.tv_sec = time->tv_sec;
@ -53,104 +33,12 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return returnvalue::OK; 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 Clock::getUptime() {
timeval uptime{}; timeval uptime{0,0};
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.
double uptimeSeconds; double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) { if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) {
uptime->tv_sec = uptimeSeconds; uptime.tv_sec = uptimeSeconds;
uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6); uptime.tv_usec = uptimeSeconds * (double)1e6 - (uptime.tv_sec * 1e6);
} }
return returnvalue::OK; return uptime;
} }
// 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;
}

View File

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

View File

@ -6,20 +6,21 @@
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/osal/rtems/RtemsBasic.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; rtems_time_of_day timeRtems;
timeRtems.year = time->year; timeRtems.year = time_tod.year;
timeRtems.month = time->month; timeRtems.month = time_tod.month;
timeRtems.day = time->day; timeRtems.day = time_tod.day;
timeRtems.hour = time->hour; timeRtems.hour = time_tod.hour;
timeRtems.minute = time->minute; timeRtems.minute = time_tod.minute;
timeRtems.second = time->second; timeRtems.second = time_tod.second;
timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; timeRtems.ticks = static_cast<uint64_t>(time_tod.usecond) * rtems_clock_get_ticks_per_second() / 1e6;
rtems_status_code status = rtems_clock_set(&timeRtems); rtems_status_code status = rtems_clock_set(&timeRtems);
switch (status) { switch (status) {
case RTEMS_SUCCESSFUL: 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) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
// Callable from ISR // Callable from ISR
rtems_status_code status = rtems_clock_get_tod_timeval(time); 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 // According to docs.rtems.org for rtems 5 this method is more accurate than
// rtems_clock_get_ticks_since_boot // rtems_clock_get_ticks_since_boot
timeval time_timeval;
timespec time; timespec time;
rtems_status_code status = rtems_clock_get_uptime(&time); rtems_status_code status = rtems_clock_get_uptime(&time);
uptime->tv_sec = time.tv_sec; time_timeval.tv_sec = time.tv_sec;
time.tv_nsec = time.tv_nsec / 1000; time_timeval.tv_usec = time.tv_nsec / 1000;
uptime->tv_usec = time.tv_nsec; return time_timeval;
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;
}

View File

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

View File

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

View File

@ -1,5 +1,5 @@
#include "fsfw/osal/rtems/BinarySemaphore.h" #include "fsfw/osal/rtems/BinarySemaphore.h"
// #include "fsfw/osal/rtems/CountingSemaphore.h" //#include "fsfw/osal/rtems/CountingSemaphore.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/tasks/SemaphoreFactory.h" #include "fsfw/tasks/SemaphoreFactory.h"
@ -18,7 +18,9 @@ SemaphoreFactory* SemaphoreFactory::instance() {
} }
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
return new BinarySemaphore(); return nullptr;
//TODO
//return new BinarySemaphore();
} }
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, uint8_t initCount, SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, uint8_t initCount,

View File

@ -9,4 +9,4 @@ target_sources(
Service17Test.cpp Service17Test.cpp
Service20ParameterManagement.cpp Service20ParameterManagement.cpp
CService200ModeCommanding.cpp CService200ModeCommanding.cpp
CServiceHealthCommanding.cpp) CService201HealthCommanding.cpp)

View File

@ -19,8 +19,7 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case (Subservice::COMMAND_MODE_COMMAND): case (Subservice::COMMAND_MODE_COMMAND):
case (Subservice::COMMAND_MODE_READ): case (Subservice::COMMAND_MODE_READ):
case (Subservice::COMMAND_MODE_ANNOUNCE): case (Subservice::COMMAND_MODE_ANNCOUNCE):
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
return returnvalue::OK; return returnvalue::OK;
default: default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE; return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
@ -54,32 +53,16 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice, ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen, const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) { uint32_t *state, object_id_t objectId) {
bool recursive = false; ModePacket modeCommandPacket;
switch (subservice) { ReturnValue_t result =
case (Subservice::COMMAND_MODE_COMMAND): { modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
ModePacket modeCommandPacket; if (result != returnvalue::OK) {
ReturnValue_t result = return result;
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
return result;
}
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND,
modeCommandPacket.getMode(), modeCommandPacket.getSubmode());
return returnvalue::OK;
}
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
recursive = true;
[[fallthrough]];
case (Subservice::COMMAND_MODE_ANNOUNCE):
ModeMessage::setModeAnnounceMessage(*message, recursive);
return EXECUTION_COMPLETE;
case (Subservice::COMMAND_MODE_READ):
ModeMessage::setModeReadMessage(*message);
return returnvalue::OK;
default:
return CommandingServiceBase::INVALID_SUBSERVICE;
} }
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
modeCommandPacket.getSubmode());
return result;
} }
ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply, ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply,
@ -90,10 +73,8 @@ ReturnValue_t CService200ModeCommanding::handleReply(const CommandMessage *reply
ReturnValue_t result = returnvalue::FAILED; ReturnValue_t result = returnvalue::FAILED;
switch (replyId) { switch (replyId) {
case (ModeMessage::REPLY_MODE_REPLY): { case (ModeMessage::REPLY_MODE_REPLY): {
if (previousCommand != ModeMessage::CMD_MODE_COMMAND) { result = prepareModeReply(reply, objectId);
return prepareModeReply(reply, objectId); break;
}
return returnvalue::OK;
} }
case (ModeMessage::REPLY_WRONG_MODE_REPLY): { case (ModeMessage::REPLY_WRONG_MODE_REPLY): {
result = prepareWrongModeReply(reply, objectId); result = prepareWrongModeReply(reply, objectId);

View File

@ -52,7 +52,7 @@ class CService200ModeCommanding : public CommandingServiceBase {
COMMAND_MODE_READ = 3, COMMAND_MODE_READ = 3,
//!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event. //!< [EXPORT] : [COMMAND] Trigger an ModeInfo Event.
//! This command does NOT have a reply //! This command does NOT have a reply
COMMAND_MODE_ANNOUNCE = 4, COMMAND_MODE_ANNCOUNCE = 4,
//!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this //!< [EXPORT] : [COMMAND] Trigger a ModeInfo Event and to send this
//! command to every child. This command does NOT have a reply. //! command to every child. This command does NOT have a reply.
COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5, COMMAND_MODE_ANNOUNCE_RECURSIVELY = 5,

View File

@ -0,0 +1,106 @@
#include "fsfw/pus/CService201HealthCommanding.h"
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthMessage.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/pus/servicepackets/Service201Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
CService201HealthCommanding::CService201HealthCommanding(object_id_t objectId, uint16_t apid,
uint8_t serviceId,
uint8_t numParallelCommands,
uint16_t commandTimeoutSeconds)
: CommandingServiceBase(objectId, apid, "PUS 201 Health MGMT", serviceId, numParallelCommands,
commandTimeoutSeconds) {}
ReturnValue_t CService201HealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
return returnvalue::OK;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Invalid Subservice" << std::endl;
#endif
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t CService201HealthCommanding::getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData,
size_t tcDataLen,
MessageQueueId_t *id,
object_id_t *objectId) {
if (tcDataLen < sizeof(object_id_t)) {
return CommandingServiceBase::INVALID_TC;
}
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
return checkInterfaceAndAcquireMessageQueue(id, objectId);
}
ReturnValue_t CService201HealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = destination->getCommandQueue();
return returnvalue::OK;
}
ReturnValue_t CService201HealthCommanding::prepareCommand(CommandMessage *message,
uint8_t subservice, const uint8_t *tcData,
size_t tcDataLen, uint32_t *state,
object_id_t objectId) {
ReturnValue_t result = returnvalue::OK;
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH): {
HealthSetCommand healthCommand;
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
break;
}
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
healthCommand.getHealth());
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE_ALL);
break;
}
default: {
// Should never happen, subservice was already checked
result = returnvalue::FAILED;
}
}
return result;
}
ReturnValue_t CService201HealthCommanding::handleReply(const CommandMessage *reply,
Command_t previousCommand, uint32_t *state,
CommandMessage *optionalNextCommand,
object_id_t objectId, bool *isStep) {
Command_t replyId = reply->getCommand();
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
return EXECUTION_COMPLETE;
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
return reply->getReplyRejectedReason();
}
return CommandingServiceBase::INVALID_REPLY;
}
// Not used for now, health state already reported by event
[[maybe_unused]] ReturnValue_t CService201HealthCommanding::prepareHealthSetReply(
const CommandMessage *reply) {
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
HealthSetReply healthSetReply(health, oldHealth);
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
}

View File

@ -1,26 +1,8 @@
#ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #ifndef FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_ #define FSFW_PUS_CSERVICE201HEALTHCOMMANDING_H_
#include <fsfw/health/HealthTable.h>
#include "fsfw/tmtcservices/CommandingServiceBase.h" #include "fsfw/tmtcservices/CommandingServiceBase.h"
struct HealthServiceCfg {
HealthServiceCfg(object_id_t objectId, uint16_t apid, object_id_t healthTable,
uint16_t maxNumHealthInfoPerCycle)
: objectId(objectId),
apid(apid),
table(healthTable),
maxNumHealthInfoPerCycle(maxNumHealthInfoPerCycle) {}
object_id_t objectId;
uint16_t apid;
object_id_t table;
uint16_t maxNumHealthInfoPerCycle;
uint8_t service = 201;
uint8_t numParallelCommands = 4;
uint16_t commandTimeoutSeconds = 60;
};
/** /**
* @brief Custom PUS service to set health of all objects * @brief Custom PUS service to set health of all objects
* implementing hasHealthIF. * implementing hasHealthIF.
@ -35,12 +17,11 @@ struct HealthServiceCfg {
* child class like this service * child class like this service
* *
*/ */
class CServiceHealthCommanding : public CommandingServiceBase { class CService201HealthCommanding : public CommandingServiceBase {
public: public:
CServiceHealthCommanding(HealthServiceCfg args); CService201HealthCommanding(object_id_t objectId, uint16_t apid, uint8_t serviceId,
~CServiceHealthCommanding() override = default; uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
~CService201HealthCommanding() override = default;
ReturnValue_t initialize() override;
protected: protected:
/* CSB abstract function implementations */ /* CSB abstract function implementations */
@ -56,14 +37,7 @@ class CServiceHealthCommanding : public CommandingServiceBase {
CommandMessage *optionalNextCommand, object_id_t objectId, CommandMessage *optionalNextCommand, object_id_t objectId,
bool *isStep) override; bool *isStep) override;
void doPeriodicOperation() override;
private: private:
const object_id_t healthTableId;
HealthTable *healthTable;
uint16_t maxNumHealthInfoPerCycle = 0;
bool reportAllHealth = false;
ReturnValue_t iterateHealthTable(bool reset);
static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet, static ReturnValue_t checkInterfaceAndAcquireMessageQueue(MessageQueueId_t *MessageQueueToSet,
const object_id_t *objectId); const object_id_t *objectId);

View File

@ -1,158 +0,0 @@
#include <fsfw/events/EventManagerIF.h>
#include <fsfw/pus/CServiceHealthCommanding.h>
#include "fsfw/health/HasHealthIF.h"
#include "fsfw/health/HealthMessage.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/pus/servicepackets/Service201Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h"
CServiceHealthCommanding::CServiceHealthCommanding(HealthServiceCfg args)
: CommandingServiceBase(args.objectId, args.apid, "PUS 201 Health MGMT", args.service,
args.numParallelCommands, args.commandTimeoutSeconds),
healthTableId(args.table),
maxNumHealthInfoPerCycle(args.maxNumHealthInfoPerCycle) {}
ReturnValue_t CServiceHealthCommanding::initialize() {
ReturnValue_t result = CommandingServiceBase::initialize();
if (result != returnvalue::OK) {
return result;
}
healthTable = ObjectManager::instance()->get<HealthTable>(healthTableId);
if (healthTable == nullptr) {
return returnvalue::FAILED;
}
return returnvalue::OK;
}
ReturnValue_t CServiceHealthCommanding::isValidSubservice(uint8_t subservice) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL):
return returnvalue::OK;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Invalid Subservice" << std::endl;
#endif
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t CServiceHealthCommanding::getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData,
size_t tcDataLen,
MessageQueueId_t *id,
object_id_t *objectId) {
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH):
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
if (tcDataLen < sizeof(object_id_t)) {
return CommandingServiceBase::INVALID_TC;
}
SerializeAdapter::deSerialize(objectId, &tcData, &tcDataLen, SerializeIF::Endianness::BIG);
return checkInterfaceAndAcquireMessageQueue(id, objectId);
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
return returnvalue::OK;
}
default: {
return returnvalue::FAILED;
}
}
}
ReturnValue_t CServiceHealthCommanding::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t *messageQueueToSet, const object_id_t *objectId) {
auto *destination = ObjectManager::instance()->get<HasHealthIF>(*objectId);
if (destination == nullptr) {
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = destination->getCommandQueue();
return returnvalue::OK;
}
ReturnValue_t CServiceHealthCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen,
uint32_t *state, object_id_t objectId) {
ReturnValue_t result = returnvalue::OK;
switch (subservice) {
case (Subservice::COMMAND_SET_HEALTH): {
HealthSetCommand healthCommand;
result = healthCommand.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
if (result != returnvalue::OK) {
break;
}
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_SET,
healthCommand.getHealth());
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH): {
HealthMessage::setHealthMessage(message, HealthMessage::HEALTH_ANNOUNCE);
break;
}
case (Subservice::COMMAND_ANNOUNCE_HEALTH_ALL): {
ReturnValue_t result = iterateHealthTable(true);
if (result == returnvalue::OK) {
reportAllHealth = true;
return EXECUTION_COMPLETE;
}
return result;
}
default: {
// Should never happen, subservice was already checked
result = returnvalue::FAILED;
}
}
return result;
}
ReturnValue_t CServiceHealthCommanding::handleReply(const CommandMessage *reply,
Command_t previousCommand, uint32_t *state,
CommandMessage *optionalNextCommand,
object_id_t objectId, bool *isStep) {
Command_t replyId = reply->getCommand();
if (replyId == HealthMessage::REPLY_HEALTH_SET) {
return EXECUTION_COMPLETE;
} else if (replyId == CommandMessageIF::REPLY_REJECTED) {
return reply->getReplyRejectedReason();
}
return CommandingServiceBase::INVALID_REPLY;
}
void CServiceHealthCommanding::doPeriodicOperation() {
if (reportAllHealth) {
for (uint8_t i = 0; i < maxNumHealthInfoPerCycle; i++) {
ReturnValue_t result = iterateHealthTable(false);
if (result != returnvalue::OK) {
reportAllHealth = false;
break;
}
}
}
}
// Not used for now, health state already reported by event
[[maybe_unused]] ReturnValue_t CServiceHealthCommanding::prepareHealthSetReply(
const CommandMessage *reply) {
auto health = static_cast<uint8_t>(HealthMessage::getHealth(reply));
auto oldHealth = static_cast<uint8_t>(HealthMessage::getOldHealth(reply));
HealthSetReply healthSetReply(health, oldHealth);
return sendTmPacket(Subservice::REPLY_HEALTH_SET, healthSetReply);
}
ReturnValue_t CServiceHealthCommanding::iterateHealthTable(bool reset) {
std::pair<object_id_t, HasHealthIF::HealthState> pair;
ReturnValue_t result = healthTable->iterate(&pair, reset);
if (result != returnvalue::OK) {
return result;
} else {
EventManagerIF::triggerEvent(pair.first, HasHealthIF::HEALTH_INFO, pair.second, pair.second);
return returnvalue::OK;
}
}

View File

@ -69,14 +69,14 @@ ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire" sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
<< "MessageQueue: Can't access object" << std::endl; << "MessageQueue: Can't access object" << std::endl;
sif::error << "Object ID: 0x" << std::hex << *objectId << std::dec << std::endl; sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl;
sif::error << "Make sure it implements ReceivesParameterMessagesIF" << std::endl; sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl;
#else #else
sif::printError( sif::printError(
"Service20ParameterManagement::checkInterfaceAndAcquire" "Service20ParameterManagement::checkInterfaceAndAcquire"
"MessageQueue: Can't access object\n"); "MessageQueue: Can't access object\n");
sif::printError("Object ID: 0x%08x\n", *objectId); sif::printError("Object ID: 0x%08x\n", *objectId);
sif::printError("Make sure it implements ReceivesParameterMessagesIF\n"); sif::printError("Make sure it implements ReceivesParameterMessagesIF!\n");
#endif #endif
return CommandingServiceBase::INVALID_OBJECT; return CommandingServiceBase::INVALID_OBJECT;

View File

@ -1,7 +1,5 @@
#include "fsfw/pus/Service9TimeManagement.h" #include "fsfw/pus/Service9TimeManagement.h"
#include <cmath>
#include "fsfw/events/EventManagerIF.h" #include "fsfw/events/EventManagerIF.h"
#include "fsfw/pus/servicepackets/Service9Packets.h" #include "fsfw/pus/servicepackets/Service9Packets.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
@ -17,17 +15,9 @@ ReturnValue_t Service9TimeManagement::performService() { return returnvalue::OK;
ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) { ReturnValue_t Service9TimeManagement::handleRequest(uint8_t subservice) {
switch (subservice) { switch (subservice) {
case Subservice::SET_TIME: { case SUBSERVICE::SET_TIME: {
return setTime(); return setTime();
} }
case Subservice::DUMP_TIME: {
timeval newTime;
Clock::getClock_timeval(&newTime);
uint32_t subsecondMs =
static_cast<uint32_t>(std::floor(static_cast<double>(newTime.tv_usec) / 1000.0));
triggerEvent(CLOCK_DUMP, newTime.tv_sec, subsecondMs);
return returnvalue::OK;
}
default: default:
return AcceptsTelecommandsIF::INVALID_SUBSERVICE; return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
} }
@ -43,14 +33,13 @@ ReturnValue_t Service9TimeManagement::setTime() {
return result; return result;
} }
timeval time; // TODO maybe switch to getClock_usecs to report more meaningful data
Clock::getClock_timeval(&time); uint32_t formerUptime = Clock::getUptime_ms();
result = Clock::setClock(&timeToSet); result = Clock::setClock(&timeToSet);
if (result == returnvalue::OK) { if (result == returnvalue::OK) {
timeval newTime; uint32_t newUptime = Clock::getUptime_ms();
Clock::getClock_timeval(&newTime); triggerEvent(CLOCK_SET, newUptime, formerUptime);
triggerEvent(CLOCK_SET, time.tv_sec, newTime.tv_sec);
return returnvalue::OK; return returnvalue::OK;
} else { } else {
triggerEvent(CLOCK_SET_FAILURE, result, 0); triggerEvent(CLOCK_SET_FAILURE, result, 0);

View File

@ -6,13 +6,10 @@
class Service9TimeManagement : public PusServiceBase { class Service9TimeManagement : public PusServiceBase {
public: public:
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
static constexpr Event CLOCK_SET =
//!< Clock has been set. P1: old timeval seconds. P2: new timeval seconds. MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO); static constexpr Event CLOCK_SET_FAILURE =
//!< Clock dump event. P1: timeval seconds P2: timeval milliseconds. MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_DUMP = MAKE_EVENT(1, severity::INFO);
//!< Clock could not be set. P1: Returncode.
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(2, severity::LOW);
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9; static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
@ -33,9 +30,8 @@ class Service9TimeManagement : public PusServiceBase {
virtual ReturnValue_t setTime(); virtual ReturnValue_t setTime();
private: private:
enum Subservice { enum SUBSERVICE {
SET_TIME = 128, //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format SET_TIME = 128 //!< [EXPORT] : [COMMAND] Time command in ASCII, CUC or CDS format
DUMP_TIME = 129,
}; };
}; };

View File

@ -10,11 +10,11 @@
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// RMAP command bits // RMAP command bits
// #define RMAP_COMMAND_BIT_INCREMENT 2 //#define RMAP_COMMAND_BIT_INCREMENT 2
// #define RMAP_COMMAND_BIT_REPLY 3 //#define RMAP_COMMAND_BIT_REPLY 3
// #define RMAP_COMMAND_BIT_WRITE 5 //#define RMAP_COMMAND_BIT_WRITE 5
// #define RMAP_COMMAND_BIT_VERIFY 4 //#define RMAP_COMMAND_BIT_VERIFY 4
// #define RMAP_COMMAND_BIT 6 //#define RMAP_COMMAND_BIT 6
namespace RMAPIds { namespace RMAPIds {
@ -32,14 +32,14 @@ static const uint8_t RMAP_COMMAND_READ = ((1 << RMAP_COMMAND_BIT) | (1 << RMAP_C
static const uint8_t RMAP_REPLY_WRITE = static const uint8_t RMAP_REPLY_WRITE =
((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY)); ((1 << RMAP_COMMAND_BIT_WRITE) | (1 << RMAP_COMMAND_BIT_REPLY));
static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY)); static const uint8_t RMAP_REPLY_READ = ((1 << RMAP_COMMAND_BIT_REPLY));
// #define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE) //#define RMAP_COMMAND_WRITE ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_WRITE)
//| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) | //| (1<<RMAP_COMMAND_BIT_REPLY)) #define RMAP_COMMAND_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT) |
//(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define //(1<<RMAP_COMMAND_BIT_WRITE) | (1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define
// RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY)) // RMAP_COMMAND_READ ((1<<RMAP_COMMAND_BIT) | (1<<RMAP_COMMAND_BIT_REPLY))
// #define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) | //#define RMAP_REPLY_WRITE ((1<<RMAP_COMMAND_BIT_WRITE) |
//(1<<RMAP_COMMAND_BIT_REPLY)) //(1<<RMAP_COMMAND_BIT_REPLY))
// #define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) | //#define RMAP_REPLY_WRITE_VERIFY ((1<<RMAP_COMMAND_BIT_WRITE) |
//(1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define RMAP_REPLY_READ //(1<<RMAP_COMMAND_BIT_REPLY) | (1<<RMAP_COMMAND_BIT_VERIFY)) #define RMAP_REPLY_READ
//((1<<RMAP_COMMAND_BIT_REPLY)) //((1<<RMAP_COMMAND_BIT_REPLY))
@ -49,9 +49,9 @@ static const uint8_t RMAP_COMMAND_HEADER_LEN = 16;
static const uint8_t RMAP_WRITE_REPLY_HEADER_LEN = 8; static const uint8_t RMAP_WRITE_REPLY_HEADER_LEN = 8;
static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12; static const uint8_t RMAP_READ_REPLY_HEADER_LEN = 12;
static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC static const uint8_t RMAP_DATA_FOOTER_SIZE = 1; // SIZE OF CRC
// #define RMAP_COMMAND_HEADER_LEN 16 //#define RMAP_COMMAND_HEADER_LEN 16
// #define RMAP_WRITE_REPLY_HEADER_LEN 8 //#define RMAP_WRITE_REPLY_HEADER_LEN 8
// #define RMAP_READ_REPLY_HEADER_LEN 12 //#define RMAP_READ_REPLY_HEADER_LEN 12
} // namespace RMAPIds } // namespace RMAPIds

View File

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

View File

@ -198,10 +198,9 @@ void Heater::setSwitch(uint8_t number, ReturnValue_t state, uint32_t* uptimeOfSw
} else { } else {
if ((*uptimeOfSwitching == INVALID_UPTIME)) { if ((*uptimeOfSwitching == INVALID_UPTIME)) {
powerSwitcher->sendSwitchCommand(number, state); powerSwitcher->sendSwitchCommand(number, state);
Clock::getUptime(uptimeOfSwitching); *uptimeOfSwitching = Clock::getUptime_ms();
} else { } else {
uint32_t currentUptime; uint32_t currentUptime = Clock::getUptime_ms();
Clock::getUptime(&currentUptime);
if (currentUptime - *uptimeOfSwitching > powerSwitcher->getSwitchDelayMs()) { if (currentUptime - *uptimeOfSwitching > powerSwitcher->getSwitchDelayMs()) {
*uptimeOfSwitching = INVALID_UPTIME; *uptimeOfSwitching = INVALID_UPTIME;
if (healthHelper.healthTable->isHealthy(getObjectId())) { if (healthHelper.healthTable->isHealthy(getObjectId())) {

View File

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

View File

@ -4,8 +4,6 @@
#include "fsfw/timemanager/Clock.h" #include "fsfw/timemanager/Clock.h"
CdsShortTimeStamper::CdsShortTimeStamper() : SystemObject(0, false) {}
CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {} CdsShortTimeStamper::CdsShortTimeStamper(object_id_t objectId) : SystemObject(objectId) {}
ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t CdsShortTimeStamper::serialize(uint8_t **buffer, size_t *size, size_t maxSize,

View File

@ -18,7 +18,6 @@
class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject { class CdsShortTimeStamper : public TimeWriterIF, public TimeReaderIF, public SystemObject {
public: public:
static constexpr size_t TIMESTAMP_LEN = 7; static constexpr size_t TIMESTAMP_LEN = 7;
CdsShortTimeStamper();
/** /**
* @brief Default constructor which also registers the time stamper as a * @brief Default constructor which also registers the time stamper as a
* system object so it can be found with the #objectManager. * system object so it can be found with the #objectManager.

View File

@ -14,8 +14,10 @@
#include <ctime> #include <ctime>
#endif #endif
class Clock { class Clock {
public: public:
// https://xkcd.com/927/
typedef struct { typedef struct {
uint32_t year; //!< Year, A.D. uint32_t year; //!< Year, A.D.
uint32_t month; //!< Month, 1 .. 12. uint32_t month; //!< Month, 1 .. 12.
@ -26,14 +28,6 @@ class Clock {
uint32_t usecond; //!< Microseconds, 0 .. 999999 uint32_t usecond; //!< Microseconds, 0 .. 999999
} TimeOfDay_t; } 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. * This system call sets the system time.
* To set the time, it uses a TimeOfDay_t struct. * 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 * Get the time since boot in a timeval struct
* *
* @param[out] time A pointer to a timeval struct where the uptime is stored. * @return 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()
*/ */
static ReturnValue_t getUptime(timeval *uptime);
static timeval getUptime(); static timeval getUptime();
/** /**
@ -79,7 +68,7 @@ class Clock {
* @param ms uptime in ms * @param ms uptime in ms
* @return returnvalue::OK on success. Otherwise, the OS failure code is returned. * @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. * Returns the time in microseconds since an OS-defined epoch.
@ -90,6 +79,7 @@ class Clock {
* - Otherwise, the OS failure code is returned. * - Otherwise, the OS failure code is returned.
*/ */
static ReturnValue_t getClock_usecs(uint64_t *time); static ReturnValue_t getClock_usecs(uint64_t *time);
/** /**
* Returns the time in a TimeOfDay_t struct. * Returns the time in a TimeOfDay_t struct.
* @param time A pointer to a TimeOfDay_t struct. * @param time A pointer to a TimeOfDay_t struct.
@ -106,6 +96,7 @@ class Clock {
* @return * @return
*/ */
static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to); static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to);
/** /**
* Converts a time of day struct to POSIX seconds. * Converts a time of day struct to POSIX seconds.
* @param time The time of day as input * @param time The time of day as input

View File

@ -1,4 +1,5 @@
#include <ctime> #include <ctime>
#include <cstdlib>
#include "fsfw/ipc/MutexGuard.h" #include "fsfw/ipc/MutexGuard.h"
#include "fsfw/timemanager/Clock.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) { ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) {
struct tm* timeInfo; struct tm time_tm;
// According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s // WINDOWS does not provide gmtime_r, but 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);
#ifdef PLATFORM_WIN #ifdef PLATFORM_WIN
time_t time; errno_t result = gmtime_s(&time_tm, &from->tv_sec);
time = from->tv_sec; if (result != 0) {
timeInfo = gmtime(&time); return returnvalue::FAILED;
}
#else #else
timeInfo = gmtime(&from->tv_sec); void* result = gmtime_r(&from->tv_sec, &time_tm);
if (result == nullptr) {
return returnvalue::FAILED;
}
#endif #endif
to->year = timeInfo->tm_year + 1900;
to->month = timeInfo->tm_mon + 1; to->year = time_tm.tm_year + 1900;
to->day = timeInfo->tm_mday; to->month = time_tm.tm_mon + 1;
to->hour = timeInfo->tm_hour; to->day = time_tm.tm_mday;
to->minute = timeInfo->tm_min; to->hour = time_tm.tm_hour;
to->second = timeInfo->tm_sec; to->minute = time_tm.tm_min;
to->second = time_tm.tm_sec;
to->usecond = from->tv_usec; to->usecond = from->tv_usec;
return returnvalue::OK; 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() { ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
MutexFactory* mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
@ -94,3 +135,37 @@ ReturnValue_t Clock::checkOrCreateClockMutex() {
} }
return returnvalue::OK; 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

@ -7,9 +7,9 @@ Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
Countdown::~Countdown() {} Countdown::~Countdown() {}
ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) {
ReturnValue_t returnValue = Clock::getUptime(&startTime); startTime = Clock::getUptime_ms();
timeout = milliseconds; timeout = milliseconds;
return returnValue; return returnvalue::OK;
} }
bool Countdown::hasTimedOut() const { bool Countdown::hasTimedOut() const {
@ -39,7 +39,5 @@ uint32_t Countdown::getRemainingMillis() const {
} }
uint32_t Countdown::getCurrentTime() const { uint32_t Countdown::getCurrentTime() const {
uint32_t currentTime; return Clock::getUptime_ms();
Clock::getUptime(&currentTime);
return currentTime;
} }

View File

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

View File

@ -3,6 +3,8 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sys/time.h>
#include "fsfw/platform.h" #include "fsfw/platform.h"

View File

@ -100,6 +100,5 @@ ReturnValue_t PusTcCreator::setSerializableUserData(const SerializeIF &serializa
void PusTcCreator::setup() { void PusTcCreator::setup() {
spCreator.setPacketType(ccsds::PacketType::TC); spCreator.setPacketType(ccsds::PacketType::TC);
spCreator.setSecHeaderFlag(); spCreator.setSecHeaderFlag();
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
updateSpLengthField(); updateSpLengthField();
} }

View File

@ -119,7 +119,6 @@ void PusTmCreator::setup() {
updateSpLengthField(); updateSpLengthField();
spCreator.setPacketType(ccsds::PacketType::TM); spCreator.setPacketType(ccsds::PacketType::TM);
spCreator.setSecHeaderFlag(); spCreator.setSecHeaderFlag();
spCreator.setSeqFlags(ccsds::SequenceFlags::UNSEGMENTED);
} }
void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) { void PusTmCreator::setMessageTypeCounter(uint16_t messageTypeCounter) {

View File

@ -348,7 +348,7 @@ void CommandingServiceBase::startExecution(store_address_t storeId, CommandMapIt
sendResult = commandQueue->sendMessage(iter.value->first, &command); sendResult = commandQueue->sendMessage(iter.value->first, &command);
} }
if (sendResult == returnvalue::OK) { if (sendResult == returnvalue::OK) {
Clock::getUptime(&iter->second.uptimeOfStart); iter->second.uptimeOfStart = Clock::getUptime_ms();
iter->second.step = 0; iter->second.step = 0;
iter->second.subservice = tcReader.getSubService(); iter->second.subservice = tcReader.getSubService();
iter->second.command = command.getCommand(); iter->second.command = command.getCommand();
@ -434,8 +434,7 @@ inline void CommandingServiceBase::doPeriodicOperation() {}
MessageQueueId_t CommandingServiceBase::getCommandQueue() { return commandQueue->getId(); } MessageQueueId_t CommandingServiceBase::getCommandQueue() { return commandQueue->getId(); }
void CommandingServiceBase::checkTimeout() { void CommandingServiceBase::checkTimeout() {
uint32_t uptime; uint32_t uptime = Clock::getUptime_ms();
Clock::getUptime(&uptime);
CommandMapIter iter; CommandMapIter iter;
for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) {
if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {

View File

@ -16,9 +16,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
tcDestination(tcDestination) tcDestination(tcDestination)
{ {
auto mqArgs = MqArgs(objectId, static_cast<void*>(this)); tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } 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) { if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored; this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
return returnvalue::OK; return returnvalue::OK;
@ -145,17 +143,13 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
#endif /* FSFW_VERBOSE_LEVEL >= 3 */ #endif /* FSFW_VERBOSE_LEVEL >= 3 */
if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) { if (communicationLinkUp == false or packetSentCounter >= sentPacketsPerCycle) {
ReturnValue_t result = storeDownlinkData(&message); storeDownlinkData(&message);
if (result != returnvalue::OK) {
tmStore->deleteData(message.getStorageId());
}
continue; continue;
} }
result = tmStore->getData(message.getStorageId(), &data, &size); result = tmStore->getData(message.getStorageId(), &data, &size);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
status = result; status = result;
tmStore->deleteData(message.getStorageId());
continue; continue;
} }
@ -163,9 +157,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
status = result; status = result;
} else { } else {
tmStore->deleteData(message.getStorageId());
packetSentCounter++; packetSentCounter++;
} }
tmStore->deleteData(message.getStorageId());
} }
return status; return status;
} }
@ -177,18 +171,15 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
} }
if (tmFifo->full()) { if (tmFifo->full()) {
if (warningSwitch) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number " sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!" "of stored packet IDs reached!"
<< std::endl; << std::endl;
#else #else
sif::printWarning( sif::printWarning(
"TmTcBridge::storeDownlinkData: TM downlink max. number " "TmTcBridge::storeDownlinkData: TM downlink max. number "
"of stored packet IDs reached!\n"); "of stored packet IDs reached!\n");
#endif #endif
warningSwitch = false;
}
if (overwriteOld) { if (overwriteOld) {
tmFifo->retrieve(&storeId); tmFifo->retrieve(&storeId);
tmStore->deleteData(storeId); tmStore->deleteData(storeId);
@ -230,7 +221,6 @@ ReturnValue_t TmTcBridge::handleStoredTm() {
packetSentCounter++; packetSentCounter++;
if (tmFifo->empty()) { if (tmFifo->empty()) {
warningSwitch = true;
tmStored = false; tmStored = false;
} }
tmStore->deleteData(storeId); tmStore->deleteData(storeId);

View File

@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
public: public:
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200;
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
@ -42,7 +42,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
* @return -@c returnvalue::OK if value was set successfully * @return -@c returnvalue::OK if value was set successfully
* -@c returnvalue::FAILED otherwise, stored value stays the same * -@c returnvalue::FAILED otherwise, stored value stays the same
*/ */
ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored); ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
/** /**
* This will set up the bridge to overwrite old data in the FIFO. * This will set up the bridge to overwrite old data in the FIFO.
@ -91,7 +91,6 @@ class TmTcBridge : public AcceptsTelemetryIF,
//! by default, so telemetry will be handled immediately. //! by default, so telemetry will be handled immediately.
bool communicationLinkUp = true; bool communicationLinkUp = true;
bool tmStored = false; bool tmStored = false;
bool warningSwitch = true;
bool overwriteOld = true; bool overwriteOld = true;
uint8_t packetSentCounter = 0; uint8_t packetSentCounter = 0;
@ -153,7 +152,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
*/ */
DynamicFIFO<store_address_t>* tmFifo = nullptr; DynamicFIFO<store_address_t>* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
}; };
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */ #endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */

View File

@ -325,12 +325,12 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
// trickery here to calculate the raw values first // trickery here to calculate the raw values first
int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8; int32_t fieldStrengthRawX = ((packet[1] << 24) | (packet[2] << 16) | (packet[3] << 8)) >> 8;
int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8; int32_t fieldStrengthRawY = ((packet[4] << 24) | (packet[5] << 16) | (packet[6] << 8)) >> 8;
int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[9] << 8)) >> 8; int32_t fieldStrengthRawZ = ((packet[7] << 24) | (packet[8] << 16) | (packet[3] << 8)) >> 8;
// Now scale to physical value in microtesla // Now scale to physical value in microtesla
float fieldStrengthX = fieldStrengthRawX * scaleFactorX; float fieldStrengthX = fieldStrengthRawX * scaleFactorX;
float fieldStrengthY = fieldStrengthRawY * scaleFactorY; float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorZ; float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
if (periodicPrintout) { if (periodicPrintout) {
if (debugDivider.checkAndIncrement()) { if (debugDivider.checkAndIncrement()) {

View File

@ -180,6 +180,10 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
} }
#else #else
#endif #endif
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
<< " bytes" << std::endl;
#endif #endif
return returnvalue::FAILED; return returnvalue::FAILED;
} }

View File

@ -20,7 +20,9 @@ add_subdirectory(globalfunctions)
add_subdirectory(timemanager) add_subdirectory(timemanager)
add_subdirectory(tmtcpacket) add_subdirectory(tmtcpacket)
add_subdirectory(cfdp) add_subdirectory(cfdp)
IF(NOT FSFW_OSAL MATCHES "rtems")
add_subdirectory(hal) add_subdirectory(hal)
ENDIF()
add_subdirectory(internalerror) add_subdirectory(internalerror)
add_subdirectory(devicehandler) add_subdirectory(devicehandler)
add_subdirectory(tmtcservices) add_subdirectory(tmtcservices)

View File

@ -10,16 +10,120 @@
#define CATCH_CONFIG_COLOUR_WINDOWS #define CATCH_CONFIG_COLOUR_WINDOWS
#include <fsfw/osal/osal.h>
#include <catch2/catch_session.hpp> #include <catch2/catch_session.hpp>
#ifdef FSFW_OSAL_FREERTOS
#include <FreeRTOS.h>
#include "task.h"
#endif
extern int customSetup(); extern int customSetup();
extern int customTeardown(); extern int customTeardown();
#ifdef FSFW_OSAL_FREERTOS
struct Taskparameters {
int argc;
char** argv;
TaskHandle_t catchTask;
} taskParameters;
void unittestTaskFunction(void* pvParameters) {
Taskparameters* parameters = (Taskparameters*)pvParameters;
int result = Catch::Session().run(parameters->argc, parameters->argv);
vTaskDelay(pdMS_TO_TICKS(10));
vTaskSuspendAll();
vTaskDelete(parameters->catchTask);
customTeardown();
exit(result);
}
#endif
#ifdef FSFW_OSAL_RTEMS
#include <signal.h>
int sigaltstack(const stack_t* ss, stack_t* old_ss) { return 0; }
extern "C" {
void exit_qemu_failing(int error) {
asm(/* 0x20026 == ADP_Stopped_ApplicationExit */
"mov x1, #0x26\n\t"
"movk x1, #2, lsl #16\n\t"
"str x1, [sp,#0]\n\t");
/* Exit status code. Host QEMU process exits with that status. */
asm("mov x0, %[error]\n\t" : : [error] "r" (error));
asm(
"str x0, [sp,#8]\n\t"
/* x1 contains the address of parameter block.
* Any memory address could be used. */
"mov x1, sp\n\t"
/* SYS_EXIT */
"mov w0, #0x18\n\t"
/* Do the semihosting call on A64. */
"hlt 0xf000\n\t"
);
}
#include <rtemsConfig.h>
void user_handle_fatal(Internal_errors_Source source, bool internal, Internal_errors_t error_code){
if ( source == RTEMS_FATAL_SOURCE_EXIT ) {
if (error_code != 0) {
printk("*** EXIT STATUS NOT ZERO ***\n");
printk("Quitting qemu with exit code %i\n", error_code);
exit_qemu_failing(error_code);
}
}
}
rtems_task Init(rtems_task_argument ignored) {
rtems_time_of_day now;
now.year = 2023;
now.month = 1;
now.day = 15;
now.hour = 0;
now.minute = 0;
now.second = 0;
now.ticks = 0;
rtems_clock_set(&now);
customSetup();
const char* argv[] = {"fsfw-test", ""};
int result = Catch::Session().run(1, argv);
customTeardown();
exit(result);
}
}
#endif
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
customSetup(); customSetup();
int result = 0;
#ifdef FSFW_OSAL_FREERTOS
xTaskCreate(
unittestTaskFunction, /* The function that implements the task. */
"Unittests", /* The text name assigned to the task - for debug only as it is not used by the
kernel. */
configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */
&taskParameters, /* The parameter passed to the task - not used in this simple case. */
1, /* The priority assigned to the task. */
&taskParameters.catchTask); /* The task handle is not required, so NULL is passed. */
taskParameters.argc = argc;
taskParameters.argv = argv;
vTaskStartScheduler();
#else
// Catch internal function call // Catch internal function call
int result = Catch::Session().run(argc, argv); result = Catch::Session().run(argc, argv);
#endif
// global clean-up // global clean-up
customTeardown(); customTeardown();

View File

@ -1,2 +1,5 @@
target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestSemaphore.cpp target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestClock.cpp)
TestClock.cpp)
if(FSFW_OSAL MATCHES "linux" OR FSFW_OSAL MATCHES "freertos")
target_sources(${FSFW_TEST_TGT} PRIVATE TestSemaphore.cpp)
endif()

View File

@ -1,5 +1,6 @@
#include <fsfw/globalfunctions/timevalOperations.h> #include <fsfw/globalfunctions/timevalOperations.h>
#include <fsfw/timemanager/Clock.h> #include <fsfw/timemanager/Clock.h>
#include <stdio.h>
#include <array> #include <array>
#include <catch2/catch_approx.hpp> #include <catch2/catch_approx.hpp>
@ -7,6 +8,8 @@
#include "CatchDefinitions.h" #include "CatchDefinitions.h"
//TODO setClock()
TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
SECTION("Test getClock") { SECTION("Test getClock") {
timeval time; timeval time;
@ -21,7 +24,7 @@ TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") {
// We require timeOfDayAsTimeval to be larger than time as it // We require timeOfDayAsTimeval to be larger than time as it
// was request a few ns later // was request a few ns later
double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time); double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time);
CHECK(difference >= 0.0); CHECK(difference >= 0);
CHECK(difference <= 0.005); CHECK(difference <= 0.005);
// Conversion in the other direction // Conversion in the other direction

View File

@ -4,8 +4,6 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
// binary semaphores currently only supported on linux
#ifdef FSFW_OSAL_LINUX
TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") {
// perform set-up here // perform set-up here
@ -33,6 +31,4 @@ TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") {
TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") { TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") {
SECTION("Simple Test") {} SECTION("Simple Test") {}
} }
#endif

View File

@ -7,7 +7,7 @@
namespace addresses { namespace addresses {
/* Logical addresses have uint32_t datatype */ /* Logical addresses have uint32_t datatype */
enum LogicAddress : address_t {}; enum logicalAddresses : address_t {};
} // namespace addresses } // namespace addresses
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */ #endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */

View File

@ -0,0 +1,102 @@
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_TICKLESS_IDLE 0
#define configTICK_RATE_HZ 1000
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE ((unsigned short)PTHREAD_STACK_MIN)
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 20
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configUSE_MINI_LIST_ITEM 1
#define configSTACK_DEPTH_TYPE uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
#define configHEAP_CLEAR_MEMORY_ON_FREE 1
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE ((size_t)(1024 * 1024))
#define configAPPLICATION_ALLOCATED_HEAP 1
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configUSE_SB_COMPLETED_CALLBACK 0
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Co-routine related definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 3
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application]
/* Define to trap errors during development. */
//#define configASSERT( ( x ) ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )
/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
#define configTOTAL_MPU_REGIONS 8 /* Default value. */
#define configTEX_S_C_B_FLASH 0x07UL /* Default value. */
#define configTEX_S_C_B_SRAM 0x07UL /* Default value. */
#define configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY 1
#define configALLOW_UNPRIVILEGED_CRITICAL_SECTIONS 1
#define configENABLE_ERRATA_837070_WORKAROUND 1
/* ARMv8-M secure side port related definitions. */
#define secureconfigMAX_SECURE_CONTEXTS 5
/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_uxTaskGetStackHighWaterMark2 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 0
#define INCLUDE_xTaskAbortDelay 0
#define INCLUDE_xTaskGetHandle 0
#define INCLUDE_xTaskResumeFromISR 1
/* A header file that defines trace macro can be included here. */
#endif /* FREERTOS_CONFIG_H */

View File

@ -0,0 +1,3 @@
add_compile_options("-mcpu=cortex-a72" "-I/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib/include")
add_link_options("-B/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib" "-qrtems")

View File

@ -0,0 +1,36 @@
## the name of the target operating system
set(CMAKE_SYSTEM_NAME a72_lp64_qemu)
set(CMAKE_SYSTEM_PROCESSOR a72)
# which compilers to use for C and C++
set(CMAKE_C_COMPILER aarch64-rtems6-gcc)
set(CMAKE_CXX_COMPILER aarch64-rtems6-g++)
# built in tests fail
set(CMAKE_C_COMPILER_WORKS 1)
set(CMAKE_CXX_COMPILER_WORKS 1)
# adjust the default behavior of the FIND_XXX() commands:
# search programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# ignore host installed libraries
# makes find_package() ignore the <package>Config.cmake files
set(CMAKE_IGNORE_PATH /usr/local)
# supress errors
add_compile_definitions("__STDC_VERSION__")
# make newlib behave like glib with an intercepted cmath
add_compile_options("-I${CMAKE_SOURCE_DIR}/unittests/testcfg/rtems/include")
# we supply an a72_lp64_qemu.cmake there
list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/unittests/testcfg/rtems/cmake")

View File

@ -0,0 +1,39 @@
#pragma once
#include_next <cmath>
extern "C++"
{
namespace std _GLIBCXX_VISIBILITY(default)
{
#undef lround
#undef erfc
#undef round
using ::lround;
long
lround(float __x);
constexpr long
lround(long double __x);
using ::erfc;
constexpr float
erfc(float __x);
constexpr long double
erfc(long double __x);
constexpr float
round(float __x);
using ::round;
constexpr long double
round(long double __x);
}
}

View File

@ -0,0 +1,32 @@
#pragma once
#include <rtems/extension.h>
#include <rtems/bspIo.h>
void user_handle_fatal(Internal_errors_Source source, bool internal, Internal_errors_t error_code);
#define RTEMS_USE_UNLIMITED_OBJECTS_ALLOCATION 0
#define CONFIGURE_MICROSECONDS_PER_TICK 1000
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_MAXIMUM_TASKS 20
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 30
#define CONFIGURE_MAXIMUM_SEMAPHORES 20
#define CONFIGURE_MAXIMUM_TIMERS 10
//! Required for Rate-Monotonic Scheduling (RMS)
#define CONFIGURE_MAXIMUM_PERIODS 15
#define CONFIGURE_INIT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 6)
//! Around 41 kB extra task stack for now.
#define CONFIGURE_EXTRA_TASK_STACKS (10 * RTEMS_MINIMUM_STACK_SIZE)
#define CONFIGURE_INITIAL_EXTENSIONS { NULL, NULL, NULL, NULL, NULL, NULL, NULL, user_handle_fatal, NULL }
#define CONFIGURE_INIT
#include <rtems.h>
#include <rtems/confdefs.h>