Compare commits

...

21 Commits

Author SHA1 Message Date
Ulrich Mohr 7426e10f82 clocks suck a little less
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-26 11:33:40 +01:00
uli 123c81777a clocks suck 2023-01-26 00:01:40 +01:00
Ulrich Mohr 6d85fa155e cleaning up unittest build
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-20 16:05:04 +01:00
Ulrich Mohr e6af6200ae updating CI
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-19 17:32:23 +01:00
Ulrich Mohr 5ca3e83934 working on rtems CI build
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-19 16:46:43 +01:00
Ulrich Mohr 6adabb059a fixing rtems cmake config
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-19 16:27:10 +01:00
Ulrich Mohr 5d0a5cd201 exiting qemu nonzero when tests fail 2023-01-19 14:47:40 +01:00
Ulrich Mohr adb8483bb0 unittests for rtems working
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-19 14:24:33 +01:00
Ulrich Mohr fdfdce2fb0 compiling, crashing when run
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-18 00:25:25 +01:00
Ulrich Mohr 90efb132d0 fixing rebase error
fsfw/fsfw/pipeline/pr-development There was a failure building this commit Details
fsfw/fsfw/pipeline/head This commit looks good Details
2023-01-16 12:41:23 +01:00
Ulrich Mohr fe9804d922 format
fsfw/fsfw/pipeline/head There was a failure building this commit Details
2023-01-16 12:35:14 +01:00
Ulrich Mohr a0eae66c35 checking if this helps docker build
fsfw/fsfw/pipeline/head There was a failure building this commit Details
2023-01-16 12:32:16 +01:00
Ulrich Mohr e131480d5f two errors found by valgrind 2023-01-16 12:32:15 +01:00
Ulrich Mohr 90bafbb6de typos in Jenkinsfile 2023-01-16 12:31:54 +01:00
Ulrich Mohr 47d85fb61c finished freertos unittests, valgrind not happy yet 2023-01-16 12:31:53 +01:00
Ulrich Mohr 39dad5f45b unittests running but failing 2023-01-16 12:31:53 +01:00
Ulrich Mohr a993c4e0d4 adding linux ci and fixing problems 2023-01-16 12:31:53 +01:00
Robin Müller fe9cc20d00 make get const 2023-01-16 12:31:53 +01:00
Robin Müller 552a12a6ad updates for source sequence counter 2023-01-16 12:31:47 +01:00
Ulrich Mohr 13639feec6 FreeRTOS unittests building (but not running) 2023-01-16 12:30:36 +01:00
Ulrich Mohr 654de0f586 WIP 2023-01-16 12:30:36 +01:00
54 changed files with 742 additions and 582 deletions

View File

@ -153,7 +153,7 @@ if(FSFW_BUILD_TESTS)
"${MSG_PREFIX} Building the FSFW unittests in addition to the static library" "${MSG_PREFIX} Building the FSFW unittests in addition to the static library"
) )
# Check whether the user has already installed Catch2 first # Check whether the user has already installed Catch2 first
find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET)
# Not installed, so use FetchContent to download and provide Catch2 # Not installed, so use FetchContent to download and provide Catch2
if(NOT Catch2_FOUND) if(NOT Catch2_FOUND)
message( message(
@ -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)
@ -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

View File

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

View File

@ -321,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];
@ -346,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);
@ -366,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);
@ -577,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();

View File

@ -23,6 +23,7 @@ EventManager::EventManager(object_id_t setObjectId)
} }
EventManager::~EventManager() { EventManager::~EventManager() {
listenerList.clear();
QueueFactory::instance()->deleteMessageQueue(eventReportQueue); QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
MutexFactory::instance()->deleteMutex(mutex); MutexFactory::instance()->deleteMutex(mutex);
} }
@ -61,9 +62,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
if (!result.second) { if (!result.second) {
return returnvalue::FAILED; return returnvalue::FAILED;
} }
return returnvalue::OK; return returnvalue::OK;
} }
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
}
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) { ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
return subscribeToEventRange(listener, event); return subscribeToEventRange(listener, event);
} }

View File

@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
MessageQueueId_t getEventReportQueue(); MessageQueueId_t getEventReportQueue();
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object); ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,

View File

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

View File

@ -23,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() {
#endif #endif
return; return;
} }
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId); manager->unregisterListener(eventQueue->getId());
QueueFactory::instance()->deleteMessageQueue(eventQueue); QueueFactory::instance()->deleteMessageQueue(eventQueue);
} }

View File

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

View File

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

View File

@ -14,7 +14,10 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t m
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); } InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex);
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
void InternalErrorReporter::setDiagnosticPrintout(bool enable) { void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
this->diagnosticPrintout = enable; this->diagnosticPrintout = enable;

View File

@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
ObjectManager::ObjectManager() = default; ObjectManager::ObjectManager() = default;
void ObjectManager::clear() {
if (objManagerInstance != nullptr) {
delete objManagerInstance;
objManagerInstance = nullptr;
}
}
ObjectManager::~ObjectManager() { ObjectManager::~ObjectManager() {
for (auto const& iter : objectList) { teardown = true;
delete iter.second; for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
delete iter->second;
} }
} }
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
} }
ReturnValue_t ObjectManager::remove(object_id_t id) { ReturnValue_t ObjectManager::remove(object_id_t id) {
// this function is called during destruction of System Objects
// disabeld for teardown to avoid iterator invalidation and
// double free
if (teardown) {
return returnvalue::OK;
}
if (this->getSystemObject(id) != nullptr) { if (this->getSystemObject(id) != nullptr) {
this->objectList.erase(id); this->objectList.erase(id);
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1

View File

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

View File

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

View File

@ -40,7 +40,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF {
void refreshTaskHandle(); 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

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

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

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

View File

@ -2,6 +2,8 @@
#include <rtems/rtems/sem.h> #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

@ -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

@ -2,12 +2,12 @@
#include <cstddef> #include <cstddef>
#include "fsfw/globalfunctions/CRC.h"
#include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serialize/SerializeAdapter.h"
#include "fsfw/serviceinterface.h" #include "fsfw/serviceinterface.h"
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h" #include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
#include "fsfw/globalfunctions/CRC.h" #include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
static constexpr auto DEF_END = SerializeIF::Endianness::BIG; static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
@ -180,7 +180,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
if (CRC::crc16ccitt(data, size) != 0) { if (CRC::crc16ccitt(data, size) != 0) {
return CONTAINED_TC_CRC_MISSMATCH; return CONTAINED_TC_CRC_MISSMATCH;
} }
// store currentPacket and receive the store address // store currentPacket and receive the store address
store_address_t addr{}; store_address_t addr{};
if (tcStore->addData(&addr, data, size) != returnvalue::OK || if (tcStore->addData(&addr, data, size) != returnvalue::OK ||

View File

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

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

@ -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

@ -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

@ -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

@ -31,4 +31,7 @@ int customSetup() {
return 0; return 0;
} }
int customTeardown() { return 0; } int customTeardown() {
ObjectManager::clear();
return 0;
}

View File

@ -9,7 +9,9 @@ DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId)
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
DeviceHandlerCommander::~DeviceHandlerCommander() {} DeviceHandlerCommander::~DeviceHandlerCommander() {
QueueFactory::instance()->deleteMessageQueue(commandQueue);
}
ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) { ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) {
readCommandQueue(); readCommandQueue();

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

@ -1,46 +1,34 @@
#include <fsfw/osal/osal.h>
#ifdef LINUX
/*
#include <fsfw/tasks/SemaphoreFactory.h> #include <fsfw/tasks/SemaphoreFactory.h>
#include <fsfw/timemanager/Stopwatch.h> #include <fsfw/timemanager/Stopwatch.h>
#include "catch.hpp" #include <catch2/catch_test_macros.hpp>
#include "core/CatchDefinitions.h"
TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") {
//perform set-up here TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") {
SemaphoreIF* binSemaph = SemaphoreFactory::instance()-> // perform set-up here
createBinarySemaphore(); SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore();
REQUIRE(binSemaph != nullptr); REQUIRE(binSemaph != nullptr);
SECTION("Simple Test") { SECTION("Simple Test") {
// set-up is run for each section // set-up is run for each section
REQUIRE(binSemaph->getSemaphoreCounter() == 1); REQUIRE(binSemaph->getSemaphoreCounter() == 1);
REQUIRE(binSemaph->release() == REQUIRE(binSemaph->release() == static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED)); REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == returnvalue::OK);
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == {
result::OK); // not precise enough on linux.. should use clock instead..
{ // Stopwatch stopwatch(false);
// not precise enough on linux.. should use clock instead.. // REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) ==
//Stopwatch stopwatch(false); // SemaphoreIF::SEMAPHORE_TIMEOUT);
//REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == // dur_millis_t time = stopwatch.stop();
// SemaphoreIF::SEMAPHORE_TIMEOUT); // CHECK(time == 5);
//dur_millis_t time = stopwatch.stop(); }
//CHECK(time == 5); REQUIRE(binSemaph->getSemaphoreCounter() == 0);
} REQUIRE(binSemaph->release() == returnvalue::OK);
REQUIRE(binSemaph->getSemaphoreCounter() == 0); }
REQUIRE(binSemaph->release() == result::OK); SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
} // perform tear-down here
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
// perform tear-down here
} }
TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") {
TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") { SECTION("Simple Test") {}
SECTION("Simple Test") { }
}
}
*/
#endif

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>