From 654de0f586075a687b9b322c541572a404a42c66 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 12 Jan 2023 17:16:17 +0100 Subject: [PATCH 01/21] WIP --- CMakeLists.txt | 22 ++++++++++++++++++++++ unittests/FreeRTOS-Config/FreeRTOSConfig.h | 0 2 files changed, 22 insertions(+) create mode 100644 unittests/FreeRTOS-Config/FreeRTOSConfig.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8308f5234..59acb05cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,6 +174,25 @@ if(FSFW_BUILD_TESTS) configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h) configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h) + if(FSFW_OSAL MATCHES "freertos") + message( + STATUS + "${MSG_PREFIX} Downloading FreeRTOS with FetchContent" + ) + include(FetchContent) + + FetchContent_Declare( + FreeRTOS + GIT_REPOSITORY https://egit.irs.uni-stuttgart.de/fsfw/FreeRTOS-LTS + GIT_TAG develop + GIT_SUBMODULES FreeRTOS/FreeRTOS-Kernel) + + list(APPEND FSFW_FETCH_CONTENT_TARGETS FreeRTOS) + + set(LIB_OS_NAME FreeRTOS) + target_include_directories(FreeRTOS PRIVATE unittests/FreeRTOS-Config) + endif() + project(${FSFW_TEST_TGT} CXX C) add_executable(${FSFW_TEST_TGT}) if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) @@ -226,6 +245,9 @@ if(FSFW_FETCH_CONTENT_TARGETS) # GitHub issue: https://github.com/catchorg/Catch2/issues/2417 set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "") endif() + + + endif() set(FSFW_CORE_INC_PATH "inc") diff --git a/unittests/FreeRTOS-Config/FreeRTOSConfig.h b/unittests/FreeRTOS-Config/FreeRTOSConfig.h new file mode 100644 index 000000000..e69de29bb From 13639feec6229446c04906d2f69849ec7ececbbd Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 13 Jan 2023 11:09:32 +0100 Subject: [PATCH 02/21] FreeRTOS unittests building (but not running) --- CMakeLists.txt | 7 +- src/fsfw/osal/freertos/BinSemaphUsingTask.h | 4 +- src/fsfw/osal/freertos/BinarySemaphore.h | 2 +- .../osal/freertos/CountingSemaphUsingTask.h | 2 +- src/fsfw/osal/freertos/FixedTimeslotTask.cpp | 4 +- src/fsfw/osal/freertos/Mutex.cpp | 2 +- src/fsfw/osal/freertos/TaskManagement.cpp | 16 +-- src/fsfw/osal/freertos/TaskManagement.h | 4 +- unittests/FreeRTOS-Config/FreeRTOSConfig.h | 0 unittests/testcfg/freertos/FreeRTOSConfig.h | 104 ++++++++++++++++++ 10 files changed, 127 insertions(+), 18 deletions(-) delete mode 100644 unittests/FreeRTOS-Config/FreeRTOSConfig.h create mode 100644 unittests/testcfg/freertos/FreeRTOSConfig.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 59acb05cb..41be31e0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,16 +181,19 @@ if(FSFW_BUILD_TESTS) ) 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) - list(APPEND FSFW_FETCH_CONTENT_TARGETS FreeRTOS) + FetchContent_MakeAvailable(FreeRTOS) set(LIB_OS_NAME FreeRTOS) - target_include_directories(FreeRTOS PRIVATE unittests/FreeRTOS-Config) + target_include_directories(FreeRTOS PUBLIC unittests/testcfg/freertos) + endif() project(${FSFW_TEST_TGT} CXX C) diff --git a/src/fsfw/osal/freertos/BinSemaphUsingTask.h b/src/fsfw/osal/freertos/BinSemaphUsingTask.h index 480296eee..340633314 100644 --- a/src/fsfw/osal/freertos/BinSemaphUsingTask.h +++ b/src/fsfw/osal/freertos/BinSemaphUsingTask.h @@ -40,7 +40,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF { void refreshTaskHandle(); ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; + uint32_t timeoutMs = 0) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() const override; static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); @@ -54,7 +54,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF { * - @c returnvalue::FAILED on failure */ ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); + TickType_t timeoutTicks = portMAX_DELAY); /** * Get handle to the task related to the semaphore. diff --git a/src/fsfw/osal/freertos/BinarySemaphore.h b/src/fsfw/osal/freertos/BinarySemaphore.h index bd1148ece..abf5da16d 100644 --- a/src/fsfw/osal/freertos/BinarySemaphore.h +++ b/src/fsfw/osal/freertos/BinarySemaphore.h @@ -51,7 +51,7 @@ class BinarySemaphore : public SemaphoreIF { * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; + uint32_t timeoutMs = 0) override; /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. diff --git a/src/fsfw/osal/freertos/CountingSemaphUsingTask.h b/src/fsfw/osal/freertos/CountingSemaphUsingTask.h index 4426f29b9..2fecfbbc5 100644 --- a/src/fsfw/osal/freertos/CountingSemaphUsingTask.h +++ b/src/fsfw/osal/freertos/CountingSemaphUsingTask.h @@ -34,7 +34,7 @@ class CountingSemaphoreUsingTask : public SemaphoreIF { * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING, - uint32_t timeoutMs = portMAX_DELAY) override; + uint32_t timeoutMs = 0) override; /** * Release a semaphore, increasing the number of available counting diff --git a/src/fsfw/osal/freertos/FixedTimeslotTask.cpp b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp index a0a4ecee3..ff111063e 100644 --- a/src/fsfw/osal/freertos/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/freertos/FixedTimeslotTask.cpp @@ -56,7 +56,9 @@ ReturnValue_t FixedTimeslotTask::startTask() { // start time for the first entry. auto slotListIter = pollingSeqTable.current; - pollingSeqTable.intializeSequenceAfterTaskCreation(); + ReturnValue_t result = pollingSeqTable.intializeSequenceAfterTaskCreation(); + // Ignore returnvalue for now + static_cast(result); // The start time for the first entry is read. uint32_t intervalMs = slotListIter->pollingTimeMs; diff --git a/src/fsfw/osal/freertos/Mutex.cpp b/src/fsfw/osal/freertos/Mutex.cpp index 6c264dd69..1b2be77c9 100644 --- a/src/fsfw/osal/freertos/Mutex.cpp +++ b/src/fsfw/osal/freertos/Mutex.cpp @@ -22,7 +22,7 @@ ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) { return MutexIF::MUTEX_NOT_FOUND; } // If the timeout type is BLOCKING, this will be the correct value. - uint32_t timeout = portMAX_DELAY; + TickType_t timeout = portMAX_DELAY; if (timeoutType == TimeoutType::POLLING) { timeout = 0; } else if (timeoutType == TimeoutType::WAITING) { diff --git a/src/fsfw/osal/freertos/TaskManagement.cpp b/src/fsfw/osal/freertos/TaskManagement.cpp index 1879976cd..b09ff721b 100644 --- a/src/fsfw/osal/freertos/TaskManagement.cpp +++ b/src/fsfw/osal/freertos/TaskManagement.cpp @@ -3,16 +3,16 @@ void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); } void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::TASK) { - if (callContext == CallContext::ISR) { - // This function depends on the partmacro.h definition for the specific device - vRequestContextSwitchFromISR(); - } else { +// if (callContext == CallContext::ISR) { +// // This function depends on the partmacro.h definition for the specific device +// vRequestContextSwitchFromISR(); +// } else { vRequestContextSwitchFromTask(); - } +// } } TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); } -size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) { - return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); -} +// size_t TaskManagement::getTaskStackHighWatermark(TaskHandle_t task) { +// return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t); +// } diff --git a/src/fsfw/osal/freertos/TaskManagement.h b/src/fsfw/osal/freertos/TaskManagement.h index 6dec15cce..44c8c0f39 100644 --- a/src/fsfw/osal/freertos/TaskManagement.h +++ b/src/fsfw/osal/freertos/TaskManagement.h @@ -11,7 +11,7 @@ * Architecture dependant portmacro.h function call. * Should be implemented in bsp. */ -extern "C" void vRequestContextSwitchFromISR(); +//extern "C" void vRequestContextSwitchFromISR(); /*! * Used by functions to tell if they are being called from @@ -53,7 +53,7 @@ TaskHandle_t getCurrentTaskHandle(); * @return Smallest value of stack remaining since the task was started in * words. */ -size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); +//size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); }; // namespace TaskManagement diff --git a/unittests/FreeRTOS-Config/FreeRTOSConfig.h b/unittests/FreeRTOS-Config/FreeRTOSConfig.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/unittests/testcfg/freertos/FreeRTOSConfig.h b/unittests/testcfg/freertos/FreeRTOSConfig.h new file mode 100644 index 000000000..ca470db0c --- /dev/null +++ b/unittests/testcfg/freertos/FreeRTOSConfig.h @@ -0,0 +1,104 @@ +#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 configCPU_CLOCK_HZ 60000000 +#define configSYSTICK_CLOCK_HZ 1000000 +#define configTICK_RATE_HZ 250 +#define configMAX_PRIORITIES 5 +#define configMINIMAL_STACK_SIZE 128 +#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 0 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 10 +#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 10240 +#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 */ \ No newline at end of file From 552a12a6ad8d57a915e7f05554a624a46eb29418 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 28 Nov 2022 08:30:45 +0100 Subject: [PATCH 03/21] updates for source sequence counter --- src/fsfw/tmtcservices/SourceSequenceCounter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/tmtcservices/SourceSequenceCounter.h b/src/fsfw/tmtcservices/SourceSequenceCounter.h index f530b4445..43b6945ca 100644 --- a/src/fsfw/tmtcservices/SourceSequenceCounter.h +++ b/src/fsfw/tmtcservices/SourceSequenceCounter.h @@ -11,7 +11,7 @@ class SourceSequenceCounter { SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {} void increment() { sequenceCount = (sequenceCount + 1) % (ccsds::LIMIT_SEQUENCE_COUNT); } void decrement() { sequenceCount = (sequenceCount - 1) % (ccsds::LIMIT_SEQUENCE_COUNT); } - uint16_t get() const { return this->sequenceCount; } + uint16_t get() { return this->sequenceCount; } void reset(uint16_t toValue = 0) { sequenceCount = toValue % (ccsds::LIMIT_SEQUENCE_COUNT); } SourceSequenceCounter& operator++(int) { this->increment(); From fe9cc20d0013c9da67cb71a9e8f1e1a53b7557bc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 19 Dec 2022 14:58:08 +0100 Subject: [PATCH 04/21] make get const --- src/fsfw/tmtcservices/SourceSequenceCounter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fsfw/tmtcservices/SourceSequenceCounter.h b/src/fsfw/tmtcservices/SourceSequenceCounter.h index 43b6945ca..f530b4445 100644 --- a/src/fsfw/tmtcservices/SourceSequenceCounter.h +++ b/src/fsfw/tmtcservices/SourceSequenceCounter.h @@ -11,7 +11,7 @@ class SourceSequenceCounter { SourceSequenceCounter(uint16_t initialSequenceCount = 0) : sequenceCount(initialSequenceCount) {} void increment() { sequenceCount = (sequenceCount + 1) % (ccsds::LIMIT_SEQUENCE_COUNT); } void decrement() { sequenceCount = (sequenceCount - 1) % (ccsds::LIMIT_SEQUENCE_COUNT); } - uint16_t get() { return this->sequenceCount; } + uint16_t get() const { return this->sequenceCount; } void reset(uint16_t toValue = 0) { sequenceCount = toValue % (ccsds::LIMIT_SEQUENCE_COUNT); } SourceSequenceCounter& operator++(int) { this->increment(); From a993c4e0d4d02b416a3e41e99a01238dec0dd9d9 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 12 Jan 2023 15:40:52 +0100 Subject: [PATCH 05/21] adding linux ci and fixing problems --- automation/Jenkinsfile | 96 +++++++++++++------ src/fsfw/events/EventManager.cpp | 6 ++ src/fsfw/events/EventManager.h | 1 + src/fsfw/events/EventManagerIF.h | 1 + src/fsfw/fdir/FailureIsolationBase.cpp | 2 +- src/fsfw/globalfunctions/matching/MatchTree.h | 41 +++++++- src/fsfw/health/HealthTable.cpp | 2 - .../internalerror/InternalErrorReporter.cpp | 7 +- src/fsfw/objectmanager/ObjectManager.cpp | 18 +++- src/fsfw/objectmanager/ObjectManager.h | 10 +- src/fsfw/osal/CMakeLists.txt | 10 +- src/fsfw/osal/linux/MessageQueue.cpp | 2 +- src/fsfw/osal/osal.h.in | 36 +++++++ unittests/CatchSetup.cpp | 5 +- .../devicehandler/DeviceHandlerCommander.cpp | 4 +- unittests/osal/TestSemaphore.cpp | 68 ++++++------- 16 files changed, 230 insertions(+), 79 deletions(-) create mode 100644 src/fsfw/osal/osal.h.in diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 271366062..64c32237f 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -1,45 +1,87 @@ pipeline { environment { - BUILDDIR = 'cmake-build-tests' + BUILDDIR_HOST = 'cmake-build-tests-host' + BUILDDIR_LINUX = 'cmake-build-tests-linux' DOCDDIR = 'cmake-build-documentation' } agent { docker { image 'fsfw-ci:d6' - args '--network host' + args '--network host --sysctl fs.mqueue.msg_max=100' } } stages { - stage('Clean') { - steps { - sh 'rm -rf $BUILDDIR' - } - } - stage('Configure') { - steps { - dir(BUILDDIR) { - sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' + stage('Host') { + stages{ + stage('Clean') { + steps { + sh 'rm -rf $BUILDDIR_HOST' + } + } + stage('Configure') { + steps { + 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('Build') { - steps { - dir(BUILDDIR) { - sh 'cmake --build . -j4' + stage('Linux') { + stages{ + stage('Clean') { + steps { + sh 'rm -rf $BUILDDIR_LINUX' + } } - } - } - stage('Unittests') { - steps { - dir(BUILDDIR) { - sh 'cmake --build . -- fsfw-tests_coverage -j4' + stage('Configure') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' + } + } } - } - } - stage('Valgrind') { - steps { - dir(BUILDDIR) { - sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + stage('Build') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake --build . -j4' + } + } + } + stage('Unittests') { + steps { + dir(BUILDDIR_LINUX) { + sh 'cmake --build . -- fsfw-tests_coverage -j4' + } + } + } + stage('Valgrind') { + steps { + dir(BUILDDIR_LINUX) { + sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' + } + } } } } diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp index f44668176..8bd26282a 100644 --- a/src/fsfw/events/EventManager.cpp +++ b/src/fsfw/events/EventManager.cpp @@ -23,6 +23,7 @@ EventManager::EventManager(object_id_t setObjectId) } EventManager::~EventManager() { + listenerList.clear(); QueueFactory::instance()->deleteMessageQueue(eventReportQueue); MutexFactory::instance()->deleteMutex(mutex); } @@ -61,9 +62,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener, if (!result.second) { return returnvalue::FAILED; } + return returnvalue::OK; } +ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) { + return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED; +} + ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) { return subscribeToEventRange(listener, event); } diff --git a/src/fsfw/events/EventManager.h b/src/fsfw/events/EventManager.h index 70245f5d1..0e6dace04 100644 --- a/src/fsfw/events/EventManager.h +++ b/src/fsfw/events/EventManager.h @@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy MessageQueueId_t getEventReportQueue(); ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false); + ReturnValue_t unregisterListener(MessageQueueId_t listener) override; ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event); ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object); ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0, diff --git a/src/fsfw/events/EventManagerIF.h b/src/fsfw/events/EventManagerIF.h index adb61f2b1..12014090a 100644 --- a/src/fsfw/events/EventManagerIF.h +++ b/src/fsfw/events/EventManagerIF.h @@ -18,6 +18,7 @@ class EventManagerIF { virtual ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false) = 0; + virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0; virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0; virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0; virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0; diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp index 28df16d89..0d3b02149 100644 --- a/src/fsfw/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -23,7 +23,7 @@ FailureIsolationBase::~FailureIsolationBase() { #endif return; } - manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId); + manager->unregisterListener(eventQueue->getId()); QueueFactory::instance()->deleteMessageQueue(eventQueue); } diff --git a/src/fsfw/globalfunctions/matching/MatchTree.h b/src/fsfw/globalfunctions/matching/MatchTree.h index 0c31cf2a5..69f660d30 100644 --- a/src/fsfw/globalfunctions/matching/MatchTree.h +++ b/src/fsfw/globalfunctions/matching/MatchTree.h @@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTree>(root.element), maxDepth(maxDepth) {} MatchTree() : BinaryTree>(), maxDepth(-1) {} - virtual ~MatchTree() {} + virtual ~MatchTree() { clear(); } virtual bool match(T number) override { return matchesTree(number); } bool matchesTree(T number) { iterator iter = this->begin(); @@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF, public BinaryTree>::rootNode; + + if (localRoot == nullptr) { + return; + } + + Node* node = localRoot->left; + + while (true) { + if (node->left != nullptr) { + node = node->left; + continue; + } + if (node->right != nullptr) { + node = node->right; + continue; + } + if (node->parent == nullptr) { + // this is the root node with no children + if (node->value != nullptr) { + cleanUpElement(iterator(node)); + } + return; + } + // leaf + { + Node* parent = node->parent; + if (parent->left == node) { + parent->left = nullptr; + } else { + parent->right = nullptr; + } + cleanUpElement(iterator(node)); + node = parent; + } + } + } + virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; } bool matchSubtree(iterator iter, T number) { diff --git a/src/fsfw/health/HealthTable.cpp b/src/fsfw/health/HealthTable.cpp index 5fb45fb9f..3fcf7f77e 100644 --- a/src/fsfw/health/HealthTable.cpp +++ b/src/fsfw/health/HealthTable.cpp @@ -6,8 +6,6 @@ HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) { mutex = MutexFactory::instance()->createMutex(); - ; - mapIterator = healthMap.begin(); } diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index b3b77366d..fb2dc8a61 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -7,14 +7,17 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth) : SystemObject(setObjectId), - commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)), poolManager(this, commandQueue), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorDataset(this) { + commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); 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) { this->diagnosticPrintout = enable; diff --git a/src/fsfw/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp index ddf5ab802..29c1b2fcc 100644 --- a/src/fsfw/objectmanager/ObjectManager.cpp +++ b/src/fsfw/objectmanager/ObjectManager.cpp @@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc, ObjectManager::ObjectManager() = default; +void ObjectManager::clear() { + if (objManagerInstance != nullptr) { + delete objManagerInstance; + objManagerInstance = nullptr; + } +} + ObjectManager::~ObjectManager() { - for (auto const& iter : objectList) { - delete iter.second; + teardown = true; + for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) { + delete iter->second; } } @@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) { } ReturnValue_t ObjectManager::remove(object_id_t id) { + // this function is called during destruction of System Objects + // disabeld for teardown to avoid iterator invalidation and + // double free + if (teardown) { + return returnvalue::OK; + } if (this->getSystemObject(id) != nullptr) { this->objectList.erase(id); #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/src/fsfw/objectmanager/ObjectManager.h b/src/fsfw/objectmanager/ObjectManager.h index e0e747924..355f5d0a4 100644 --- a/src/fsfw/objectmanager/ObjectManager.h +++ b/src/fsfw/objectmanager/ObjectManager.h @@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF { using produce_function_t = void (*)(void* args); /** - * Returns the single instance of TaskFactory. + * Returns the single instance of ObjectManager. * The implementation of #instance is found in its subclasses. * Thus, we choose link-time variability of the instance. */ static ObjectManager* instance(); + /** + * Deletes the single instance of ObjectManager + */ + static void clear(); + void setObjectFactoryFunction(produce_function_t prodFunc, void* args); template @@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF { */ std::map objectList; static ObjectManager* objManagerInstance; + // used when the OM itself is deleted to modify behaviour of remove() + // to avoid iterator invalidation and double free + bool teardown = false; }; // Documentation can be found in the class method declaration above diff --git a/src/fsfw/osal/CMakeLists.txt b/src/fsfw/osal/CMakeLists.txt index 50fd61025..a40976496 100644 --- a/src/fsfw/osal/CMakeLists.txt +++ b/src/fsfw/osal/CMakeLists.txt @@ -1,10 +1,13 @@ # Check the OS_FSFW variable if(FSFW_OSAL MATCHES "freertos") add_subdirectory(freertos) + set(FSFW_OSAL_FREERTOS 1) elseif(FSFW_OSAL MATCHES "rtems") add_subdirectory(rtems) + set(FSFW_OSAL_RTEMS 1) elseif(FSFW_OSAL MATCHES "linux") add_subdirectory(linux) + set(FSFW_OSAL_LINUX 1) elseif(FSFW_OSAL MATCHES "host") add_subdirectory(host) if(WIN32) @@ -13,16 +16,17 @@ elseif(FSFW_OSAL MATCHES "host") # We still need to pull in some Linux specific sources target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp) endif() - + set(FSFW_OSAL_HOST 1) else() - message(WARNING "The OS_FSFW variable was not set. Assuming host OS..") # Not set. Assumuing this is a host build, try to determine host OS if(WIN32) add_subdirectory(host) add_subdirectory(windows) + set(FSFW_OSAL_HOST 1) elseif(UNIX) add_subdirectory(linux) + set(FSFW_OSAL_LINUX 1) else() # MacOS or other OSes have not been tested yet / are not supported. message(FATAL_ERROR "The host OS could not be determined! Aborting.") @@ -31,3 +35,5 @@ else() endif() add_subdirectory(common) + +configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h) diff --git a/src/fsfw/osal/linux/MessageQueue.cpp b/src/fsfw/osal/linux/MessageQueue.cpp index b2cca3f1c..c08e37752 100644 --- a/src/fsfw/osal/linux/MessageQueue.cpp +++ b/src/fsfw/osal/linux/MessageQueue.cpp @@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs* attributes.mq_msgsize = maxMessageSize; attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open // Set the name of the queue. The slash is mandatory! - sprintf(name, "/FSFW_MQ%u\n", queueCounter++); + sprintf(name, "/FSFW_MQ%u", queueCounter++); // Create a nonblocking queue if the name is available (the queue is read // and writable for the owner as well as the group) diff --git a/src/fsfw/osal/osal.h.in b/src/fsfw/osal/osal.h.in new file mode 100644 index 000000000..8e48c31a5 --- /dev/null +++ b/src/fsfw/osal/osal.h.in @@ -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 + } +}; \ No newline at end of file diff --git a/unittests/CatchSetup.cpp b/unittests/CatchSetup.cpp index 4f2a4a54b..fc5bb3f57 100644 --- a/unittests/CatchSetup.cpp +++ b/unittests/CatchSetup.cpp @@ -31,4 +31,7 @@ int customSetup() { return 0; } -int customTeardown() { return 0; } +int customTeardown() { + ObjectManager::clear(); + return 0; +} diff --git a/unittests/devicehandler/DeviceHandlerCommander.cpp b/unittests/devicehandler/DeviceHandlerCommander.cpp index 03ff992cf..835faf2b2 100644 --- a/unittests/devicehandler/DeviceHandlerCommander.cpp +++ b/unittests/devicehandler/DeviceHandlerCommander.cpp @@ -9,7 +9,9 @@ DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId) QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } -DeviceHandlerCommander::~DeviceHandlerCommander() {} +DeviceHandlerCommander::~DeviceHandlerCommander() { + QueueFactory::instance()->deleteMessageQueue(commandQueue); +} ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) { readCommandQueue(); diff --git a/unittests/osal/TestSemaphore.cpp b/unittests/osal/TestSemaphore.cpp index 376b08dbe..1d8758b18 100644 --- a/unittests/osal/TestSemaphore.cpp +++ b/unittests/osal/TestSemaphore.cpp @@ -1,46 +1,38 @@ - -#ifdef LINUX - -/* +#include #include #include -#include "catch.hpp" -#include "core/CatchDefinitions.h" +#include -TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") { - //perform set-up here - SemaphoreIF* binSemaph = SemaphoreFactory::instance()-> - createBinarySemaphore(); - REQUIRE(binSemaph != nullptr); - SECTION("Simple Test") { - // set-up is run for each section - REQUIRE(binSemaph->getSemaphoreCounter() == 1); - REQUIRE(binSemaph->release() == - static_cast(SemaphoreIF::SEMAPHORE_NOT_OWNED)); - REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == - result::OK); - { - // not precise enough on linux.. should use clock instead.. - //Stopwatch stopwatch(false); - //REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == - // SemaphoreIF::SEMAPHORE_TIMEOUT); - //dur_millis_t time = stopwatch.stop(); - //CHECK(time == 5); - } - REQUIRE(binSemaph->getSemaphoreCounter() == 0); - REQUIRE(binSemaph->release() == result::OK); - } - SemaphoreFactory::instance()->deleteSemaphore(binSemaph); - // perform tear-down here +// binary semaphores currently only supported on linux +#ifdef FSFW_OSAL_LINUX + +TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { + // perform set-up here + SemaphoreIF* binSemaph = SemaphoreFactory::instance()->createBinarySemaphore(); + REQUIRE(binSemaph != nullptr); + SECTION("Simple Test") { + // set-up is run for each section + REQUIRE(binSemaph->getSemaphoreCounter() == 1); + REQUIRE(binSemaph->release() == static_cast(SemaphoreIF::SEMAPHORE_NOT_OWNED)); + REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) == returnvalue::OK); + { + // not precise enough on linux.. should use clock instead.. + // Stopwatch stopwatch(false); + // REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) == + // SemaphoreIF::SEMAPHORE_TIMEOUT); + // dur_millis_t time = stopwatch.stop(); + // CHECK(time == 5); + } + REQUIRE(binSemaph->getSemaphoreCounter() == 0); + REQUIRE(binSemaph->release() == returnvalue::OK); + } + SemaphoreFactory::instance()->deleteSemaphore(binSemaph); + // perform tear-down here } - -TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") { - SECTION("Simple Test") { - - } +TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") { + SECTION("Simple Test") {} } -*/ -#endif +#endif \ No newline at end of file From 39dad5f45b8bd4ee4a256d510d75ead86ccae2a9 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 13 Jan 2023 12:48:14 +0100 Subject: [PATCH 06/21] unittests running but failing --- CMakeLists.txt | 6 ++- unittests/CatchRunner.cpp | 42 ++++++++++++++++++++- unittests/CatchSetup.cpp | 2 + unittests/osal/TestSemaphore.cpp | 2 +- unittests/testcfg/freertos/FreeRTOSConfig.h | 2 +- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41be31e0c..b22ffe464 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,7 +174,7 @@ if(FSFW_BUILD_TESTS) configure_file(unittests/testcfg/FSFWConfig.h.in FSFWConfig.h) configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h) - if(FSFW_OSAL MATCHES "freertos") + if(FSFW_OSAL MATCHES "freertos") message( STATUS "${MSG_PREFIX} Downloading FreeRTOS with FetchContent" @@ -193,7 +193,6 @@ if(FSFW_BUILD_TESTS) set(LIB_OS_NAME FreeRTOS) target_include_directories(FreeRTOS PUBLIC unittests/testcfg/freertos) - endif() project(${FSFW_TEST_TGT} CXX C) @@ -385,6 +384,9 @@ if(FSFW_BUILD_TESTS) endif() target_link_libraries(${FSFW_TEST_TGT} PRIVATE Catch2::Catch2 ${LIB_FSFW_NAME}) + if(FSFW_OSAL MATCHES "freertos") + target_link_libraries(${FSFW_TEST_TGT} PRIVATE FreeRTOS) + endif() endif() # The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it. If diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index 9bdcb676a..5149f8b53 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -11,15 +11,55 @@ #define CATCH_CONFIG_COLOUR_WINDOWS #include +#include + +#ifdef FSFW_OSAL_FREERTOS + #include + #include "task.h" +#endif extern int customSetup(); extern int customTeardown(); + +#ifdef FSFW_OSAL_FREERTOS +struct Taskparameters { + int argc; char** argv; +} taskParameters; + +void unittestTaskFunction( void *pvParameters ) { + puts("go"); + Taskparameters* parameters = (Taskparameters*)pvParameters; + int result = Catch::Session().run(parameters->argc, parameters->argv); + puts("gone"); + vTaskDelete( NULL ); +} +#endif + + int main(int argc, char* argv[]) { customSetup(); + int result = 0; + + puts("pre"); + + #ifdef FSFW_OSAL_FREERTOS + puts("task"); + 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. */ + NULL ); /* The task handle is not required, so NULL is passed. */ + taskParameters.argc = argc; + taskParameters.argv = argv; + vTaskStartScheduler(); + #else + puts("nom"); // Catch internal function call - int result = Catch::Session().run(argc, argv); + result = Catch::Session().run(argc, argv); + #endif // global clean-up customTeardown(); diff --git a/unittests/CatchSetup.cpp b/unittests/CatchSetup.cpp index fc5bb3f57..cbed8029e 100644 --- a/unittests/CatchSetup.cpp +++ b/unittests/CatchSetup.cpp @@ -6,6 +6,8 @@ #include #endif + + #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/storagemanager/StorageManagerIF.h" diff --git a/unittests/osal/TestSemaphore.cpp b/unittests/osal/TestSemaphore.cpp index 1d8758b18..6bf63f6a8 100644 --- a/unittests/osal/TestSemaphore.cpp +++ b/unittests/osal/TestSemaphore.cpp @@ -5,7 +5,7 @@ #include // binary semaphores currently only supported on linux -#ifdef FSFW_OSAL_LINUX +#if defined(FSFW_OSAL_LINUX) || defined(FSFW_OSAL_FREERTOS) TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { // perform set-up here diff --git a/unittests/testcfg/freertos/FreeRTOSConfig.h b/unittests/testcfg/freertos/FreeRTOSConfig.h index ca470db0c..0c4d78f8a 100644 --- a/unittests/testcfg/freertos/FreeRTOSConfig.h +++ b/unittests/testcfg/freertos/FreeRTOSConfig.h @@ -16,7 +16,7 @@ #define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 0 -#define configUSE_COUNTING_SEMAPHORES 0 +#define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ #define configQUEUE_REGISTRY_SIZE 10 #define configUSE_QUEUE_SETS 0 From 47d85fb61cb66f2f0418d2de4d222a847697846a Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 13 Jan 2023 16:30:47 +0100 Subject: [PATCH 07/21] finished freertos unittests, valgrind not happy yet --- automation/Jenkinsfile | 93 +++++++-------------- src/fsfw/osal/freertos/Clock.cpp | 6 +- src/fsfw/timemanager/CCSDSTime.cpp | 5 +- unittests/CatchRunner.cpp | 18 ++-- unittests/osal/TestClock.cpp | 2 + unittests/testcfg/freertos/FreeRTOSConfig.h | 10 +-- 6 files changed, 48 insertions(+), 86 deletions(-) diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 64c32237f..b97c3a9a8 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -2,6 +2,7 @@ pipeline { environment { BUILDDIR_HOST = 'cmake-build-tests-host' BUILDDIR_LINUX = 'cmake-build-tests-linux' + BUILDDIR_FREERTOS = 'cmake-build-tests-freertos' DOCDDIR = 'cmake-build-documentation' } agent { @@ -12,76 +13,38 @@ pipeline { } stages { stage('Host') { - stages{ - stage('Clean') { - steps { - sh 'rm -rf $BUILDDIR_HOST' - } - } - stage('Configure') { - steps { - 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' - } - } + steps { + sh 'rm -rf $BUILDDIR_HOST' + + dir(BUILDDIR_LINUX) { + sh 'cmake -DFSFW_OSAL=host -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('Linux') { - stages{ - stage('Clean') { - steps { - sh 'rm -rf $BUILDDIR_LINUX' - } + steps { + sh 'rm -rf $BUILDDIR_HOST' + + dir(BUILDDIR_HOST) { + 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) { - sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' - } - } - } - stage('Build') { - steps { - dir(BUILDDIR_LINUX) { - sh 'cmake --build . -j4' - } - } - } - stage('Unittests') { - steps { - dir(BUILDDIR_LINUX) { - sh 'cmake --build . -- fsfw-tests_coverage -j4' - } - } - } - stage('Valgrind') { - steps { - dir(BUILDDIR_LINUX) { - sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests' - } - } + } + } + stage('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' } } } diff --git a/src/fsfw/osal/freertos/Clock.cpp b/src/fsfw/osal/freertos/Clock.cpp index dc00ac7ea..4ff340f56 100644 --- a/src/fsfw/osal/freertos/Clock.cpp +++ b/src/fsfw/osal/freertos/Clock.cpp @@ -110,11 +110,13 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* time_tm.tm_min = from->minute; time_tm.tm_sec = from->second; - time_t seconds = mktime(&time_tm); + 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; } diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index cb0d57587..4ee5362a5 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -552,10 +552,7 @@ ReturnValue_t CCSDSTime::convertFromCDS(timeval* to, const CCSDSTime::CDS_short* if (to == nullptr or from == nullptr) { return returnvalue::FAILED; } - uint16_t days = (from->dayMSB << 8) + from->dayLSB; - if (days <= DAYS_CCSDS_TO_UNIX_EPOCH) { - return INVALID_TIME_FORMAT; - } + int32_t days = (from->dayMSB << 8) + from->dayLSB; days -= DAYS_CCSDS_TO_UNIX_EPOCH; to->tv_sec = days * SECONDS_PER_DAY; uint32_t msDay = diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index 5149f8b53..8478efbf6 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -24,15 +24,19 @@ extern int customTeardown(); #ifdef FSFW_OSAL_FREERTOS struct Taskparameters { - int argc; char** argv; + int argc; char** argv;TaskHandle_t catchTask; } taskParameters; void unittestTaskFunction( void *pvParameters ) { - puts("go"); Taskparameters* parameters = (Taskparameters*)pvParameters; + int result = Catch::Session().run(parameters->argc, parameters->argv); - puts("gone"); - vTaskDelete( NULL ); + + vTaskDelay(pdMS_TO_TICKS(10)); + vTaskSuspendAll(); + vTaskDelete(parameters->catchTask); + customTeardown(); + exit(result); } #endif @@ -42,21 +46,17 @@ int main(int argc, char* argv[]) { int result = 0; - puts("pre"); - #ifdef FSFW_OSAL_FREERTOS - puts("task"); 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. */ - NULL ); /* The task handle is not required, so NULL is passed. */ + &taskParameters.catchTask); /* The task handle is not required, so NULL is passed. */ taskParameters.argc = argc; taskParameters.argv = argv; vTaskStartScheduler(); #else - puts("nom"); // Catch internal function call result = Catch::Session().run(argc, argv); #endif diff --git a/unittests/osal/TestClock.cpp b/unittests/osal/TestClock.cpp index 5d198db1a..663bcf331 100644 --- a/unittests/osal/TestClock.cpp +++ b/unittests/osal/TestClock.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include "CatchDefinitions.h" TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { diff --git a/unittests/testcfg/freertos/FreeRTOSConfig.h b/unittests/testcfg/freertos/FreeRTOSConfig.h index 0c4d78f8a..2f58e3545 100644 --- a/unittests/testcfg/freertos/FreeRTOSConfig.h +++ b/unittests/testcfg/freertos/FreeRTOSConfig.h @@ -4,11 +4,9 @@ #define configUSE_PREEMPTION 1 #define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 #define configUSE_TICKLESS_IDLE 0 -#define configCPU_CLOCK_HZ 60000000 -#define configSYSTICK_CLOCK_HZ 1000000 -#define configTICK_RATE_HZ 250 +#define configTICK_RATE_HZ 1000 #define configMAX_PRIORITIES 5 -#define configMINIMAL_STACK_SIZE 128 +#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 @@ -18,7 +16,7 @@ #define configUSE_RECURSIVE_MUTEXES 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ -#define configQUEUE_REGISTRY_SIZE 10 +#define configQUEUE_REGISTRY_SIZE 20 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 @@ -32,7 +30,7 @@ /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 -#define configTOTAL_HEAP_SIZE 10240 +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 1024 * 1024 ) ) #define configAPPLICATION_ALLOCATED_HEAP 1 #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 From 90bafbb6de9fe08095703dbab25b04ce876ea581 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 13 Jan 2023 17:37:22 +0100 Subject: [PATCH 08/21] typos in Jenkinsfile --- automation/Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index b97c3a9a8..0768f2cc2 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -16,7 +16,7 @@ pipeline { steps { sh 'rm -rf $BUILDDIR_HOST' - dir(BUILDDIR_LINUX) { + dir(BUILDDIR_HOST) { sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..' sh 'cmake --build . -j4' sh 'cmake --build . -- fsfw-tests_coverage -j4' @@ -26,9 +26,9 @@ pipeline { } stage('Linux') { steps { - sh 'rm -rf $BUILDDIR_HOST' + sh 'rm -rf $BUILDDIR_LINUX' - dir(BUILDDIR_HOST) { + 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' From e131480d5f0986dfcbf2f02a8e49dc9a2f5673c2 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 16 Jan 2023 11:36:33 +0100 Subject: [PATCH 09/21] two errors found by valgrind --- src/fsfw/internalerror/InternalErrorReporter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index fb2dc8a61..483ee72be 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -10,7 +10,6 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t m poolManager(this, commandQueue), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorDataset(this) { - commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); mutex = MutexFactory::instance()->createMutex(); } From a0eae66c351d1bf5968d83977b301589fca3f4cf Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 16 Jan 2023 11:55:13 +0100 Subject: [PATCH 10/21] checking if this helps docker build --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b22ffe464..075dc51f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,6 +193,9 @@ if(FSFW_BUILD_TESTS) 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) From fe9804d922fb3b4625c277dd2b7c5acdfbd4e1ba Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 16 Jan 2023 12:35:14 +0100 Subject: [PATCH 11/21] format --- CMakeLists.txt | 7 +- src/fsfw/osal/freertos/BinSemaphUsingTask.h | 2 +- src/fsfw/osal/freertos/TaskManagement.cpp | 12 +- src/fsfw/osal/freertos/TaskManagement.h | 4 +- .../pus/Service11TelecommandScheduling.tpp | 6 +- unittests/CatchRunner.cpp | 40 ++--- unittests/CatchSetup.cpp | 2 - unittests/osal/TestClock.cpp | 3 +- unittests/testcfg/freertos/FreeRTOSConfig.h | 142 +++++++++--------- 9 files changed, 107 insertions(+), 111 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 075dc51f7..bdf3fdc40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,10 +175,7 @@ if(FSFW_BUILD_TESTS) configure_file(unittests/testcfg/TestsConfig.h.in tests/TestsConfig.h) if(FSFW_OSAL MATCHES "freertos") - message( - STATUS - "${MSG_PREFIX} Downloading FreeRTOS with FetchContent" - ) + message(STATUS "${MSG_PREFIX} Downloading FreeRTOS with FetchContent") include(FetchContent) set(FreeRTOS_PORT posix) @@ -251,8 +248,6 @@ if(FSFW_FETCH_CONTENT_TARGETS) set_target_properties(Catch2 PROPERTIES DEBUG_POSTFIX "") endif() - - endif() set(FSFW_CORE_INC_PATH "inc") diff --git a/src/fsfw/osal/freertos/BinSemaphUsingTask.h b/src/fsfw/osal/freertos/BinSemaphUsingTask.h index 340633314..d1b82703d 100644 --- a/src/fsfw/osal/freertos/BinSemaphUsingTask.h +++ b/src/fsfw/osal/freertos/BinSemaphUsingTask.h @@ -54,7 +54,7 @@ class BinarySemaphoreUsingTask : public SemaphoreIF { * - @c returnvalue::FAILED on failure */ ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType = TimeoutType::BLOCKING, - TickType_t timeoutTicks = portMAX_DELAY); + TickType_t timeoutTicks = portMAX_DELAY); /** * Get handle to the task related to the semaphore. diff --git a/src/fsfw/osal/freertos/TaskManagement.cpp b/src/fsfw/osal/freertos/TaskManagement.cpp index b09ff721b..144985b9a 100644 --- a/src/fsfw/osal/freertos/TaskManagement.cpp +++ b/src/fsfw/osal/freertos/TaskManagement.cpp @@ -3,12 +3,12 @@ void TaskManagement::vRequestContextSwitchFromTask() { vTaskDelay(0); } void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::TASK) { -// if (callContext == CallContext::ISR) { -// // This function depends on the partmacro.h definition for the specific device -// vRequestContextSwitchFromISR(); -// } else { - vRequestContextSwitchFromTask(); -// } + // if (callContext == CallContext::ISR) { + // // This function depends on the partmacro.h definition for the specific device + // vRequestContextSwitchFromISR(); + // } else { + vRequestContextSwitchFromTask(); + // } } TaskHandle_t TaskManagement::getCurrentTaskHandle() { return xTaskGetCurrentTaskHandle(); } diff --git a/src/fsfw/osal/freertos/TaskManagement.h b/src/fsfw/osal/freertos/TaskManagement.h index 44c8c0f39..7a6b1700a 100644 --- a/src/fsfw/osal/freertos/TaskManagement.h +++ b/src/fsfw/osal/freertos/TaskManagement.h @@ -11,7 +11,7 @@ * Architecture dependant portmacro.h function call. * Should be implemented in bsp. */ -//extern "C" void vRequestContextSwitchFromISR(); +// extern "C" void vRequestContextSwitchFromISR(); /*! * Used by functions to tell if they are being called from @@ -53,7 +53,7 @@ TaskHandle_t getCurrentTaskHandle(); * @return Smallest value of stack remaining since the task was started in * words. */ -//size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); +// size_t getTaskStackHighWatermark(TaskHandle_t task = nullptr); }; // namespace TaskManagement diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp index 540f6c689..ac08f02ca 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.tpp +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -2,12 +2,12 @@ #include +#include "fsfw/globalfunctions/CRC.h" #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serialize/SerializeAdapter.h" #include "fsfw/serviceinterface.h" -#include "fsfw/tmtcservices/AcceptsTelecommandsIF.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; @@ -180,7 +180,7 @@ inline ReturnValue_t Service11TelecommandScheduling::doInsertActivi if (CRC::crc16ccitt(data, size) != 0) { return CONTAINED_TC_CRC_MISSMATCH; } - + // store currentPacket and receive the store address store_address_t addr{}; if (tcStore->addData(&addr, data, size) != returnvalue::OK || diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index 8478efbf6..a25d523d6 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -10,28 +10,31 @@ #define CATCH_CONFIG_COLOUR_WINDOWS -#include #include +#include + #ifdef FSFW_OSAL_FREERTOS - #include - #include "task.h" +#include + +#include "task.h" #endif extern int customSetup(); extern int customTeardown(); - #ifdef FSFW_OSAL_FREERTOS struct Taskparameters { - int argc; char** argv;TaskHandle_t catchTask; + int argc; + char** argv; + TaskHandle_t catchTask; } taskParameters; -void unittestTaskFunction( void *pvParameters ) { +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); @@ -40,26 +43,27 @@ void unittestTaskFunction( void *pvParameters ) { } #endif - int main(int argc, char* argv[]) { 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. */ +#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 +#else // Catch internal function call result = Catch::Session().run(argc, argv); - #endif +#endif // global clean-up customTeardown(); diff --git a/unittests/CatchSetup.cpp b/unittests/CatchSetup.cpp index cbed8029e..fc5bb3f57 100644 --- a/unittests/CatchSetup.cpp +++ b/unittests/CatchSetup.cpp @@ -6,8 +6,6 @@ #include #endif - - #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/storagemanager/StorageManagerIF.h" diff --git a/unittests/osal/TestClock.cpp b/unittests/osal/TestClock.cpp index 663bcf331..bdfefde63 100644 --- a/unittests/osal/TestClock.cpp +++ b/unittests/osal/TestClock.cpp @@ -1,12 +1,11 @@ #include #include +#include #include #include #include -#include - #include "CatchDefinitions.h" TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { diff --git a/unittests/testcfg/freertos/FreeRTOSConfig.h b/unittests/testcfg/freertos/FreeRTOSConfig.h index 2f58e3545..049bbc25e 100644 --- a/unittests/testcfg/freertos/FreeRTOSConfig.h +++ b/unittests/testcfg/freertos/FreeRTOSConfig.h @@ -1,101 +1,101 @@ #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H -#define configUSE_PREEMPTION 1 +#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 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 +#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 +#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 +#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 +#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 +#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 +#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 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 +#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 +#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 +#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. */ From 90efb132d07f14bee464b9055c2745aa73f6b8c7 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Mon, 16 Jan 2023 12:41:23 +0100 Subject: [PATCH 12/21] fixing rebase error --- src/fsfw/internalerror/InternalErrorReporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index 483ee72be..806c6b587 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -7,6 +7,7 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth) : SystemObject(setObjectId), + commandQueue(QueueFactory::instance()->createMessageQueue(messageQueueDepth)), poolManager(this, commandQueue), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorDataset(this) { From fdfdce2fb0e09c88259e82f273daa6548a322ed4 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Wed, 18 Jan 2023 00:25:25 +0100 Subject: [PATCH 13/21] compiling, crashing when run --- cmake/Platform/aarch64-rtems6.cmake | 3 ++ src/fsfw/osal/rtems/CpuUsage.cpp | 8 ++-- src/fsfw/osal/rtems/InternalErrorCodes.cpp | 7 ++-- src/fsfw/timemanager/TimeReaderIF.h | 2 + unittests/CatchRunner.cpp | 38 ++++++++++++++++++ .../rtems/cmake/rtems-qemu-toolchain.cmake | 23 +++++++++++ unittests/testcfg/rtems/include/cmath | 39 +++++++++++++++++++ 7 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 cmake/Platform/aarch64-rtems6.cmake create mode 100644 unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake create mode 100644 unittests/testcfg/rtems/include/cmath diff --git a/cmake/Platform/aarch64-rtems6.cmake b/cmake/Platform/aarch64-rtems6.cmake new file mode 100644 index 000000000..1d6b84007 --- /dev/null +++ b/cmake/Platform/aarch64-rtems6.cmake @@ -0,0 +1,3 @@ +add_compile_options("-mcpu=cortex-a72" "-I/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib/include" "-I/home/mohr/data/git/fsfw/unittests/testcfg/rtems/include") + +add_link_options("-B/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib" "-qrtems") diff --git a/src/fsfw/osal/rtems/CpuUsage.cpp b/src/fsfw/osal/rtems/CpuUsage.cpp index 4ffc22717..776d3586b 100644 --- a/src/fsfw/osal/rtems/CpuUsage.cpp +++ b/src/fsfw/osal/rtems/CpuUsage.cpp @@ -93,8 +93,8 @@ ReturnValue_t CpuUsage::serialize(uint8_t** buffer, size_t* size, size_t maxSize streamEndianness); } -uint32_t CpuUsage::getSerializedSize() const { - uint32_t size = 0; +size_t CpuUsage::getSerializedSize() const { + size_t size = 0; size += sizeof(timeSinceLastReset); size += SerialArrayListAdapter::getSerializedSize(&threadData); @@ -136,8 +136,8 @@ ReturnValue_t CpuUsage::ThreadData::serialize(uint8_t** buffer, size_t* size, si return returnvalue::OK; } -uint32_t CpuUsage::ThreadData::getSerializedSize() const { - uint32_t size = 0; +size_t CpuUsage::ThreadData::getSerializedSize() const { + size_t size = 0; size += sizeof(id); size += MAX_LENGTH_OF_THREAD_NAME; diff --git a/src/fsfw/osal/rtems/InternalErrorCodes.cpp b/src/fsfw/osal/rtems/InternalErrorCodes.cpp index 9e0c1ae77..659840f9c 100644 --- a/src/fsfw/osal/rtems/InternalErrorCodes.cpp +++ b/src/fsfw/osal/rtems/InternalErrorCodes.cpp @@ -35,10 +35,9 @@ ReturnValue_t InternalErrorCodes::translate(uint8_t code) { return OUT_OF_PROXIES; case INTERNAL_ERROR_INVALID_GLOBAL_ID: return INVALID_GLOBAL_ID; -#ifndef STM32H743ZI_NUCLEO - case INTERNAL_ERROR_BAD_STACK_HOOK: - return BAD_STACK_HOOK; -#endif + //TODO this one is not there anymore in rtems-6 (5 as well?) + //case INTERNAL_ERROR_BAD_STACK_HOOK: + // return BAD_STACK_HOOK; // case INTERNAL_ERROR_BAD_ATTRIBUTES: // return BAD_ATTRIBUTES; // case INTERNAL_ERROR_IMPLEMENTATION_KEY_CREATE_INCONSISTENCY: diff --git a/src/fsfw/timemanager/TimeReaderIF.h b/src/fsfw/timemanager/TimeReaderIF.h index aa64b7548..b66f470fb 100644 --- a/src/fsfw/timemanager/TimeReaderIF.h +++ b/src/fsfw/timemanager/TimeReaderIF.h @@ -3,6 +3,8 @@ #include #include +#include + #include "fsfw/platform.h" diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index a25d523d6..b6017b430 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -43,6 +43,44 @@ void unittestTaskFunction(void* pvParameters) { } #endif +#ifdef FSFW_OSAL_RTEMS +#include + +int sigaltstack(const stack_t * ss, stack_t * old_ss){ + return 0; +} +extern "C" { + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_UNLIMITED_OBJECTS +#define CONFIGURE_UNIFIED_WORK_AREAS + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include + + +#include +#include +#include + +rtems_task Init( + rtems_task_argument ignored +) +{ + printf( "\nHello World\n" ); + char* argv[] = {"fsfw-test"}; + int result = Catch::Session().run(1, argv); + exit( result ); +} + +} +#endif + int main(int argc, char* argv[]) { customSetup(); diff --git a/unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake b/unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake new file mode 100644 index 000000000..b75ca5d0d --- /dev/null +++ b/unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake @@ -0,0 +1,23 @@ +# the name of the target operating system +set(CMAKE_SYSTEM_NAME aarch64-rtems6) + +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++) + +set(CMAKE_C_COMPILER_WORKS 1) +set(CMAKE_CXX_COMPILER_WORKS 1) + +# where is the target environment located +#set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc +# /home/alex/mingw-install) + +# adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +# search headers and libraries in the target environment +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/unittests/testcfg/rtems/include/cmath b/unittests/testcfg/rtems/include/cmath new file mode 100644 index 000000000..a62ea66ba --- /dev/null +++ b/unittests/testcfg/rtems/include/cmath @@ -0,0 +1,39 @@ +#pragma once + +#include_next + +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); +} +} From adb8483bb0a1a6403a9c9e81b32dc8b709a6aac1 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 19 Jan 2023 14:24:33 +0100 Subject: [PATCH 14/21] unittests for rtems working --- src/fsfw/osal/rtems/Clock.cpp | 5 +-- unittests/CMakeLists.txt | 2 + unittests/CatchRunner.cpp | 63 +++++++++++++++++---------- unittests/osal/TestClock.cpp | 11 ++++- unittests/testcfg/rtems/rtemsConfig.h | 25 +++++++++++ 5 files changed, 77 insertions(+), 29 deletions(-) create mode 100644 unittests/testcfg/rtems/rtemsConfig.h diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index cb7bd0429..1ffed9871 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -107,9 +107,6 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { 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; @@ -140,7 +137,7 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* timeRtems.hour = from->hour; timeRtems.minute = from->minute; timeRtems.second = from->second; - timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6; + timeRtems.ticks = from->usecond * rtems_clock_get_ticks_per_second() / 1e6; to->tv_sec = _TOD_To_seconds(&timeRtems); to->tv_usec = from->usecond; return returnvalue::OK; diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index ad26e3923..e02e76494 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -20,7 +20,9 @@ add_subdirectory(globalfunctions) add_subdirectory(timemanager) add_subdirectory(tmtcpacket) add_subdirectory(cfdp) +IF(NOT FSFW_OSAL MATCHES "rtems") add_subdirectory(hal) +ENDIF() add_subdirectory(internalerror) add_subdirectory(devicehandler) add_subdirectory(tmtcservices) diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index b6017b430..59dde71ec 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -46,38 +46,53 @@ void unittestTaskFunction(void* pvParameters) { #ifdef FSFW_OSAL_RTEMS #include -int sigaltstack(const stack_t * ss, stack_t * old_ss){ - return 0; -} +int sigaltstack(const stack_t* ss, stack_t* old_ss) { return 0; } extern "C" { -#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER -#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER +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"); -#define CONFIGURE_UNLIMITED_OBJECTS -#define CONFIGURE_UNIFIED_WORK_AREAS + /* 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" -#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + /* x1 contains the address of parameter block. + * Any memory address could be used. */ + "mov x1, sp\n\t" -#define CONFIGURE_INIT + /* SYS_EXIT */ + "mov w0, #0x18\n\t" -#include - - -#include -#include -#include - -rtems_task Init( - rtems_task_argument ignored -) -{ - printf( "\nHello World\n" ); - char* argv[] = {"fsfw-test"}; - int result = Catch::Session().run(1, argv); - exit( result ); + /* Do the semihosting call on A64. */ + "hlt 0xf000\n\t" +); } +#include "testcfg/rtems/rtemsConfig.h" + +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(); + if (result != 0) { + exit_qemu_failing(result); + } + exit(result); +} } #endif diff --git a/unittests/osal/TestClock.cpp b/unittests/osal/TestClock.cpp index bdfefde63..5e381e8bf 100644 --- a/unittests/osal/TestClock.cpp +++ b/unittests/osal/TestClock.cpp @@ -8,6 +8,8 @@ #include "CatchDefinitions.h" +//TODO setClock() + TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { SECTION("Test getClock") { timeval time; @@ -22,7 +24,14 @@ TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { // We require timeOfDayAsTimeval to be larger than time as it // was request a few ns later double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time); - CHECK(difference >= 0.0); + uint32_t ticksPerSecond =Clock:: getTicksPerSecond(); + float secondPerTick = 0; + if (ticksPerSecond != 0){ + secondPerTick = 1.0 / ticksPerSecond; + } + // In rtems, timevals have microsecond resolution, while TOD has only tick resolution, leading to + // negative differences when comparing "equal" times + CHECK(difference >= -secondPerTick); CHECK(difference <= 0.005); // Conversion in the other direction diff --git a/unittests/testcfg/rtems/rtemsConfig.h b/unittests/testcfg/rtems/rtemsConfig.h new file mode 100644 index 000000000..e9af11079 --- /dev/null +++ b/unittests/testcfg/rtems/rtemsConfig.h @@ -0,0 +1,25 @@ +#pragma once + +#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_INIT + +#include +#include From 5d0a5cd2014f0bf2a5f3aa4b01e3a01b68bd48db Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 19 Jan 2023 14:47:40 +0100 Subject: [PATCH 15/21] exiting qemu nonzero when tests fail --- unittests/CatchRunner.cpp | 13 ++++++++++--- unittests/testcfg/rtems/rtemsConfig.h | 7 +++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index 59dde71ec..37767b5fe 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -74,6 +74,16 @@ void exit_qemu_failing(int error) { #include "testcfg/rtems/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; @@ -88,9 +98,6 @@ rtems_task Init(rtems_task_argument ignored) { const char* argv[] = {"fsfw-test", ""}; int result = Catch::Session().run(1, argv); customTeardown(); - if (result != 0) { - exit_qemu_failing(result); - } exit(result); } } diff --git a/unittests/testcfg/rtems/rtemsConfig.h b/unittests/testcfg/rtems/rtemsConfig.h index e9af11079..5988258e5 100644 --- a/unittests/testcfg/rtems/rtemsConfig.h +++ b/unittests/testcfg/rtems/rtemsConfig.h @@ -1,5 +1,10 @@ #pragma once + +#include +#include +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 @@ -19,6 +24,8 @@ //! 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 From 6adabb059a684bb4e744b9b6e2bd1172d6a36563 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 19 Jan 2023 16:27:10 +0100 Subject: [PATCH 16/21] fixing rtems cmake config --- .../testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake | 2 +- ...oolchain.cmake => aarch64-rtems6-toolchain.cmake} | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) rename cmake/Platform/aarch64-rtems6.cmake => unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake (60%) rename unittests/testcfg/rtems/cmake/{rtems-qemu-toolchain.cmake => aarch64-rtems6-toolchain.cmake} (74%) diff --git a/cmake/Platform/aarch64-rtems6.cmake b/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake similarity index 60% rename from cmake/Platform/aarch64-rtems6.cmake rename to unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake index 1d6b84007..3d5b74959 100644 --- a/cmake/Platform/aarch64-rtems6.cmake +++ b/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake @@ -1,3 +1,3 @@ -add_compile_options("-mcpu=cortex-a72" "-I/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib/include" "-I/home/mohr/data/git/fsfw/unittests/testcfg/rtems/include") +add_compile_options("-mcpu=cortex-a72" "-I/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib/include" "-I${CMAKE_SOURCE_DIR}/unittests/testcfg/rtems/include") add_link_options("-B/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib" "-qrtems") diff --git a/unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake b/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake similarity index 74% rename from unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake rename to unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake index b75ca5d0d..34f2a1409 100644 --- a/unittests/testcfg/rtems/cmake/rtems-qemu-toolchain.cmake +++ b/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake @@ -1,5 +1,5 @@ # the name of the target operating system -set(CMAKE_SYSTEM_NAME aarch64-rtems6) +set(CMAKE_SYSTEM_NAME a72_lp64_qemu) set(CMAKE_SYSTEM_PROCESSOR a72) @@ -10,10 +10,6 @@ set(CMAKE_CXX_COMPILER aarch64-rtems6-g++) set(CMAKE_C_COMPILER_WORKS 1) set(CMAKE_CXX_COMPILER_WORKS 1) -# where is the target environment located -#set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc -# /home/alex/mingw-install) - # adjust the default behavior of the FIND_XXX() commands: # search programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -21,3 +17,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search headers and libraries in the target environment set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +# supress errors +add_compile_definitions("__STDC_VERSION__") + +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/unittests/testcfg/rtems/cmake") From 5ca3e83934b8e55b43971216dae7f32e76fcb9b5 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 19 Jan 2023 16:39:30 +0100 Subject: [PATCH 17/21] working on rtems CI build --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bdf3fdc40..2ab58fae6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,7 +153,11 @@ if(FSFW_BUILD_TESTS) "${MSG_PREFIX} Building the FSFW unittests in addition to the static library" ) # Check whether the user has already installed Catch2 first + # Suppress this check for rtems, because rtems is cross compiled + # on CI with preinstalled Catch which needs to be cross compiled + if(NOT FSFW_OSAL MATCHES "rtems") find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) + endif() # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) message( @@ -217,7 +221,11 @@ message( ) # Check whether the user has already installed ETL first +# Suppress this check for rtems, because rtems is cross compiled +# on CI with preinstalled etl which is not found when cross compiling +if(NOT FSFW_OSAL MATCHES "rtems") find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) +endif() # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message( From e6af6200ae538268cde1da2e035b3cc737aabf59 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 19 Jan 2023 17:32:23 +0100 Subject: [PATCH 18/21] updating CI --- automation/Dockerfile | 8 ++++++-- automation/Jenkinsfile | 14 +++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/automation/Dockerfile b/automation/Dockerfile index 1bd39b3fb..0404bde92 100644 --- a/automation/Dockerfile +++ b/automation/Dockerfile @@ -5,7 +5,7 @@ RUN apt-get --yes upgrade #tzdata is a dependency, won't install otherwise ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync +RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping python3 pip doxygen graphviz rsync wget qemu-system-arm RUN python3 -m pip install sphinx breathe @@ -21,8 +21,12 @@ RUN git clone https://github.com/ETLCPP/etl.git && \ cmake -B build . && \ cmake --install build/ +RUN wget -qO- https://buggy.irs.uni-stuttgart.de/rtems_releases/rtems6-12.2.1.tar.bz2 | tar -xj -C /opt/ + +ENV PATH="$PATH:/opt/rtems/6/bin" + #ssh needs a valid user to work -RUN adduser --uid 114 jenkins +RUN adduser -q --uid 114 jenkins #add documentation server to known hosts RUN echo "|1|/LzCV4BuTmTb2wKnD146l9fTKgQ=|NJJtVjvWbtRt8OYqFgcYRnMQyVw= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNL8ssTonYtgiR/6RRlSIK9WU1ywOcJmxFTLcEblAwH7oifZzmYq3XRfwXrgfMpylEfMFYfCU8JRqtmi19xc21A=" >> /etc/ssh/ssh_known_hosts diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile index 0768f2cc2..cdc0ec3f0 100644 --- a/automation/Jenkinsfile +++ b/automation/Jenkinsfile @@ -3,11 +3,12 @@ pipeline { BUILDDIR_HOST = 'cmake-build-tests-host' BUILDDIR_LINUX = 'cmake-build-tests-linux' BUILDDIR_FREERTOS = 'cmake-build-tests-freertos' + BUILDDIR_RTEMS = 'cmake-build-tests-rtems' DOCDDIR = 'cmake-build-documentation' } agent { docker { - image 'fsfw-ci:d6' + image 'fsfw-ci:d7' args '--network host --sysctl fs.mqueue.msg_max=100' } } @@ -48,6 +49,17 @@ pipeline { } } } + stage('rtems') { + steps { + sh 'rm -rf $BUILDDIR_RTEMS' + + dir(BUILDDIR_RTEMS) { + sh 'cmake -DFSFW_OSAL=rtems -DFSFW_BUILD_TESTS=ON -DFSFW_TESTS_GEN_COV=OFF -DFSFW_CICD_BUILD=ON -DCMAKE_TOOLCHAIN_FILE=../unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake ..' + sh 'cmake --build . -j4' + sh 'qemu-system-aarch64 -no-reboot -nographic -serial mon:stdio -semihosting -machine virt,gic-version=3 -cpu cortex-a72 -m 4000 -kernel fsfw-tests' + } + } + } stage('Documentation') { when { branch 'development' From 6d85fa155e5edbe0fc871504d93896d7324500d3 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Fri, 20 Jan 2023 16:05:04 +0100 Subject: [PATCH 19/21] cleaning up unittest build --- CMakeLists.txt | 10 +--------- src/fsfw/osal/rtems/BinarySemaphore.cpp | 2 ++ src/fsfw/osal/rtems/SemaphoreFactory.cpp | 4 +++- unittests/CatchRunner.cpp | 2 +- unittests/osal/CMakeLists.txt | 7 +++++-- unittests/osal/TestSemaphore.cpp | 6 +----- .../rtems/cmake/Platform/a72_lp64_qemu.cmake | 2 +- .../rtems/cmake/aarch64-rtems6-toolchain.cmake | 15 +++++++++++++-- .../testcfg/rtems/{ => include}/rtemsConfig.h | 0 9 files changed, 27 insertions(+), 21 deletions(-) rename unittests/testcfg/rtems/{ => include}/rtemsConfig.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ab58fae6..c9feb0da7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,11 +153,7 @@ if(FSFW_BUILD_TESTS) "${MSG_PREFIX} Building the FSFW unittests in addition to the static library" ) # Check whether the user has already installed Catch2 first - # Suppress this check for rtems, because rtems is cross compiled - # on CI with preinstalled Catch which needs to be cross compiled - if(NOT FSFW_OSAL MATCHES "rtems") - find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION}) - endif() + find_package(Catch2 ${FSFW_CATCH2_LIB_MAJOR_VERSION} QUIET) # Not installed, so use FetchContent to download and provide Catch2 if(NOT Catch2_FOUND) message( @@ -221,11 +217,7 @@ message( ) # Check whether the user has already installed ETL first -# Suppress this check for rtems, because rtems is cross compiled -# on CI with preinstalled etl which is not found when cross compiling -if(NOT FSFW_OSAL MATCHES "rtems") find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET) -endif() # Not installed, so use FetchContent to download and provide etl if(NOT ${FSFW_ETL_LIB_NAME}_FOUND) message( diff --git a/src/fsfw/osal/rtems/BinarySemaphore.cpp b/src/fsfw/osal/rtems/BinarySemaphore.cpp index 3677dd22e..200c3095c 100644 --- a/src/fsfw/osal/rtems/BinarySemaphore.cpp +++ b/src/fsfw/osal/rtems/BinarySemaphore.cpp @@ -2,6 +2,8 @@ #include +//TODO + BinarySemaphore::BinarySemaphore() {} BinarySemaphore::~BinarySemaphore() {} diff --git a/src/fsfw/osal/rtems/SemaphoreFactory.cpp b/src/fsfw/osal/rtems/SemaphoreFactory.cpp index 35099ddce..8bc2a9117 100644 --- a/src/fsfw/osal/rtems/SemaphoreFactory.cpp +++ b/src/fsfw/osal/rtems/SemaphoreFactory.cpp @@ -18,7 +18,9 @@ SemaphoreFactory* SemaphoreFactory::instance() { } SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { - return new BinarySemaphore(); + return nullptr; + //TODO + //return new BinarySemaphore(); } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, uint8_t initCount, diff --git a/unittests/CatchRunner.cpp b/unittests/CatchRunner.cpp index 37767b5fe..a909bd9db 100644 --- a/unittests/CatchRunner.cpp +++ b/unittests/CatchRunner.cpp @@ -72,7 +72,7 @@ void exit_qemu_failing(int error) { ); } -#include "testcfg/rtems/rtemsConfig.h" +#include void user_handle_fatal(Internal_errors_Source source, bool internal, Internal_errors_t error_code){ if ( source == RTEMS_FATAL_SOURCE_EXIT ) { diff --git a/unittests/osal/CMakeLists.txt b/unittests/osal/CMakeLists.txt index 90eea2c7e..b021bacb6 100644 --- a/unittests/osal/CMakeLists.txt +++ b/unittests/osal/CMakeLists.txt @@ -1,2 +1,5 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestSemaphore.cpp - TestClock.cpp) +target_sources(${FSFW_TEST_TGT} PRIVATE testMq.cpp TestClock.cpp) + +if(FSFW_OSAL MATCHES "linux" OR FSFW_OSAL MATCHES "freertos") +target_sources(${FSFW_TEST_TGT} PRIVATE TestSemaphore.cpp) +endif() diff --git a/unittests/osal/TestSemaphore.cpp b/unittests/osal/TestSemaphore.cpp index 6bf63f6a8..ab47cdab4 100644 --- a/unittests/osal/TestSemaphore.cpp +++ b/unittests/osal/TestSemaphore.cpp @@ -4,8 +4,6 @@ #include -// binary semaphores currently only supported on linux -#if defined(FSFW_OSAL_LINUX) || defined(FSFW_OSAL_FREERTOS) TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { // perform set-up here @@ -33,6 +31,4 @@ TEST_CASE("Binary Semaphore Test", "[BinSemaphore]") { TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") { SECTION("Simple Test") {} -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake b/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake index 3d5b74959..04675df0d 100644 --- a/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake +++ b/unittests/testcfg/rtems/cmake/Platform/a72_lp64_qemu.cmake @@ -1,3 +1,3 @@ -add_compile_options("-mcpu=cortex-a72" "-I/opt/rtems/6/aarch64-rtems6/a72_lp64_qemu/lib/include" "-I${CMAKE_SOURCE_DIR}/unittests/testcfg/rtems/include") +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") diff --git a/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake b/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake index 34f2a1409..00ad2b696 100644 --- a/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake +++ b/unittests/testcfg/rtems/cmake/aarch64-rtems6-toolchain.cmake @@ -1,4 +1,4 @@ -# the name of the target operating system +## the name of the target operating system set(CMAKE_SYSTEM_NAME a72_lp64_qemu) set(CMAKE_SYSTEM_PROCESSOR a72) @@ -7,19 +7,30 @@ set(CMAKE_SYSTEM_PROCESSOR a72) 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 NEVER) +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 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") diff --git a/unittests/testcfg/rtems/rtemsConfig.h b/unittests/testcfg/rtems/include/rtemsConfig.h similarity index 100% rename from unittests/testcfg/rtems/rtemsConfig.h rename to unittests/testcfg/rtems/include/rtemsConfig.h From 123c81777ac4c69547997cacb54e4f11cbd51a30 Mon Sep 17 00:00:00 2001 From: uli Date: Thu, 26 Jan 2023 00:01:40 +0100 Subject: [PATCH 20/21] clocks suck --- src/fsfw/osal/freertos/Clock.cpp | 81 --------------------- src/fsfw/osal/host/Clock.cpp | 95 +----------------------- src/fsfw/osal/linux/Clock.cpp | 104 +-------------------------- src/fsfw/osal/rtems/Clock.cpp | 77 +++----------------- src/fsfw/timemanager/Clock.h | 21 ++---- src/fsfw/timemanager/ClockCommon.cpp | 103 ++++++++++++++++++++------ src/fsfw/timemanager/Stopwatch.cpp | 7 +- unittests/osal/TestClock.cpp | 9 +-- 8 files changed, 105 insertions(+), 392 deletions(-) diff --git a/src/fsfw/osal/freertos/Clock.cpp b/src/fsfw/osal/freertos/Clock.cpp index 4ff340f56..ec7ac999a 100644 --- a/src/fsfw/osal/freertos/Clock.cpp +++ b/src/fsfw/osal/freertos/Clock.cpp @@ -11,19 +11,6 @@ // TODO sanitize input? // TODO much of this code can be reused for tick-only systems -uint32_t Clock::getTicksPerSecond(void) { return 1000; } - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - timeval time_timeval; - - ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval); - if (result != returnvalue::OK) { - return result; - } - - return setClock(&time_timeval); -} - ReturnValue_t Clock::setClock(const timeval* time) { timeval uptime = getUptime(); @@ -44,83 +31,15 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getUptime(timeval* uptime) { - *uptime = getUptime(); - - return returnvalue::OK; -} - timeval Clock::getUptime() { TickType_t ticksSinceStart = xTaskGetTickCount(); return Timekeeper::ticksToTimeval(ticksSinceStart); } -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - timeval uptime = getUptime(); - *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; - return returnvalue::OK; -} - // uint32_t Clock::getUptimeSeconds() { // timeval uptime = getUptime(); // return uptime.tv_sec; // } -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - timeval time_timeval; - ReturnValue_t result = getClock_timeval(&time_timeval); - if (result != returnvalue::OK) { - return result; - } - *time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec; - return returnvalue::OK; -} -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - timeval time_timeval; - ReturnValue_t result = getClock_timeval(&time_timeval); - if (result != returnvalue::OK) { - return result; - } - struct tm time_tm; - gmtime_r(&time_timeval.tv_sec, &time_tm); - - time->year = time_tm.tm_year + 1900; - time->month = time_tm.tm_mon + 1; - time->day = time_tm.tm_mday; - - time->hour = time_tm.tm_hour; - time->minute = time_tm.tm_min; - time->second = time_tm.tm_sec; - - time->usecond = time_timeval.tv_usec; - - return returnvalue::OK; -} - -ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) { - struct tm time_tm = {}; - - time_tm.tm_year = from->year - 1900; - time_tm.tm_mon = from->month - 1; - time_tm.tm_mday = from->day; - - time_tm.tm_hour = from->hour; - time_tm.tm_min = from->minute; - time_tm.tm_sec = from->second; - - time_tm.tm_isdst = 0; - - time_t seconds = timegm(&time_tm); - - to->tv_sec = seconds; - 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; -} diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index dbf6529c9..c1f017c48 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -15,27 +15,6 @@ using SystemClock = std::chrono::system_clock; -uint32_t Clock::getTicksPerSecond(void) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Clock::getTicksPerSecond: Not implemented for host OSAL" << std::endl; -#else - sif::printWarning("Clock::getTicksPerSecond: Not implemented for host OSAL\n"); -#endif - /* To avoid division by zero */ - return 1; -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - /* I don't know why someone would need to set a clock which is probably perfectly fine on a - host system with internet access so this is not implemented for now. */ -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl; -#else - sif::printWarning("Clock::setClock: Not implemented for host OSAL\n"); -#endif - return returnvalue::OK; -} - ReturnValue_t Clock::setClock(const timeval* time) { /* I don't know why someone would need to set a clock which is probably perfectly fine on a host system with internet access so this is not implemented for now. */ @@ -66,6 +45,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { time->tv_usec = timeUnix.tv_nsec / 1000.0; return returnvalue::OK; #else +#warning Clock::getClock_timeval() not implemented for your platform #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl; #else @@ -75,15 +55,6 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { #endif } -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - if (time == nullptr) { - return returnvalue::FAILED; - } - using namespace std::chrono; - *time = duration_cast(system_clock::now().time_since_epoch()).count(); - return returnvalue::OK; -} - timeval Clock::getUptime() { timeval timeval; #if defined(PLATFORM_WIN) @@ -100,6 +71,7 @@ timeval Clock::getUptime() { timeval.tv_usec = uptimeSeconds * (double)1e6 - (timeval.tv_sec * 1e6); } #else +#warning Clock::getUptime() not implemented for your platform #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; #endif @@ -107,66 +79,3 @@ timeval Clock::getUptime() { return timeval; } -ReturnValue_t Clock::getUptime(timeval* uptime) { - *uptime = getUptime(); - return returnvalue::OK; -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - timeval uptime = getUptime(); - *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; - return returnvalue::OK; -} - -ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { - /* Do some magic with chrono (C++20!) */ - /* Right now, the library doesn't have the new features to get the required values yet. - so we work around that for now. */ - auto now = SystemClock::now(); - auto seconds = std::chrono::time_point_cast(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(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; -} diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index bfdcf4e20..c7c92415b 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -10,26 +10,6 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/serviceinterface/ServiceInterface.h" -uint32_t Clock::getTicksPerSecond() { - uint32_t ticks = sysconf(_SC_CLK_TCK); - return ticks; -} - -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { - timespec timeUnix{}; - timeval timeTimeval{}; - convertTimeOfDayToTimeval(time, &timeTimeval); - timeUnix.tv_sec = timeTimeval.tv_sec; - timeUnix.tv_nsec = (__syscall_slong_t)timeTimeval.tv_usec * 1000; - - int status = clock_settime(CLOCK_REALTIME, &timeUnix); - if (status != 0) { - // TODO errno - return returnvalue::FAILED; - } - return returnvalue::OK; -} - ReturnValue_t Clock::setClock(const timeval* time) { timespec timeUnix{}; timeUnix.tv_sec = time->tv_sec; @@ -53,37 +33,14 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getClock_usecs(uint64_t* time) { - timeval timeVal{}; - ReturnValue_t result = getClock_timeval(&timeVal); - if (result != returnvalue::OK) { - return result; - } - *time = static_cast(timeVal.tv_sec) * 1e6 + timeVal.tv_usec; - - return returnvalue::OK; -} - timeval Clock::getUptime() { - timeval uptime{}; - auto result = getUptime(&uptime); - if (result != returnvalue::OK) { -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Clock::getUptime: Error getting uptime" << std::endl; -#endif - } - return uptime; -} - -ReturnValue_t Clock::getUptime(timeval* uptime) { - // TODO This is not posix compatible and delivers only seconds precision - // Linux specific file read but more precise. + timeval uptime{0,0}; double uptimeSeconds; if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) { uptime->tv_sec = uptimeSeconds; uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6); } - return returnvalue::OK; + return uptime; } // Wait for new FSFW Clock function delivering seconds uptime. @@ -97,60 +54,3 @@ ReturnValue_t Clock::getUptime(timeval* uptime) { // 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; -} diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index 1ffed9871..d5d61ef78 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -34,24 +34,12 @@ 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; + TimeOfDay_t time_tod; + ReturnValue_t result = convertTimevalToTimeOfDay(time, &time_tod); + if (result != returnvalue::OK) { + return result; } - 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; + return setClock(&time_tod); } ReturnValue_t Clock::getClock_timeval(timeval* time) { @@ -73,8 +61,7 @@ ReturnValue_t Clock::getUptime(timeval* uptime) { timespec time; rtems_status_code status = rtems_clock_get_uptime(&time); uptime->tv_sec = time.tv_sec; - time.tv_nsec = time.tv_nsec / 1000; - uptime->tv_usec = time.tv_nsec; + uptime->tv_usec = time.tv_nsec / 1000; switch (status) { case RTEMS_SUCCESSFUL: return returnvalue::OK; @@ -84,8 +71,9 @@ ReturnValue_t Clock::getUptime(timeval* uptime) { } ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - // This counter overflows after 50 days - *uptimeMs = rtems_clock_get_ticks_since_boot(); + // 32bit counter overflows after 50 days + uint64_t uptime = rtems_clock_get_uptime_nanoseconds() / 1e6; + *uptimeMs = uptime & 0xffffffff; return returnvalue::OK; } @@ -100,50 +88,3 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { 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: { - time->day = timeRtems.day; - time->hour = timeRtems.hour; - time->minute = timeRtems.minute; - time->month = timeRtems.month; - time->second = timeRtems.second; - time->usecond = - static_cast(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 * rtems_clock_get_ticks_per_second() / 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; -} diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index 83bc3d9f8..4c6828e4b 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -14,8 +14,10 @@ #include #endif + class Clock { public: + // https://xkcd.com/927/ typedef struct { uint32_t year; //!< Year, A.D. uint32_t month; //!< Month, 1 .. 12. @@ -26,14 +28,6 @@ class Clock { uint32_t usecond; //!< Microseconds, 0 .. 999999 } TimeOfDay_t; - /** - * This method returns the number of clock ticks per second. - * In RTEMS, this is typically 1000. - * @return The number of ticks. - * - * @deprecated, we should not worry about ticks, but only time - */ - static uint32_t getTicksPerSecond(); /** * This system call sets the system time. * To set the time, it uses a TimeOfDay_t struct. @@ -61,13 +55,8 @@ class Clock { /** * Get the time since boot in a timeval struct * - * @param[out] time A pointer to a timeval struct where the uptime is stored. - * @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned. - * - * @deprecated, I do not think this should be able to fail, use timeval getUptime() + * @return a timeval struct where the uptime is stored */ - static ReturnValue_t getUptime(timeval *uptime); - static timeval getUptime(); /** @@ -79,7 +68,7 @@ class Clock { * @param ms uptime in ms * @return returnvalue::OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t getUptime(uint32_t *uptimeMs); + static uint32_t getUptime_ms(); /** * Returns the time in microseconds since an OS-defined epoch. @@ -90,6 +79,7 @@ class Clock { * - Otherwise, the OS failure code is returned. */ static ReturnValue_t getClock_usecs(uint64_t *time); + /** * Returns the time in a TimeOfDay_t struct. * @param time A pointer to a TimeOfDay_t struct. @@ -106,6 +96,7 @@ class Clock { * @return */ static ReturnValue_t convertTimevalToTimeOfDay(const timeval *from, TimeOfDay_t *to); + /** * Converts a time of day struct to POSIX seconds. * @param time The time of day as input diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index d0ac90043..a35848277 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -53,34 +53,61 @@ ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { } ReturnValue_t Clock::convertTimevalToTimeOfDay(const timeval* from, TimeOfDay_t* to) { - struct tm* timeInfo; - // According to https://en.cppreference.com/w/c/chrono/gmtime, the implementation of gmtime_s - // in the Windows CRT is incompatible with the C standard but this should not be an issue for - // this implementation - ReturnValue_t result = checkOrCreateClockMutex(); - if (result != returnvalue::OK) { - return result; - } - // gmtime writes its output in a global buffer which is not Thread Safe - // Therefore we have to use a Mutex here - MutexGuard helper(timeMutex); + struct tm time_tm; + // WINDOWS does not provide gmtime_r, but gmtime_s #ifdef PLATFORM_WIN - time_t time; - time = from->tv_sec; - timeInfo = gmtime(&time); + errno_t result = gmtime_s(&time_tm, &from->tv_sec); + if (result != 0) { + return returnvalue::FAILED; + } #else - timeInfo = gmtime(&from->tv_sec); + void* result = gmtime_r(&from->tv_sec, &time_tm); + + if (result == nullptr) { + return returnvalue::FAILED; + } #endif - to->year = timeInfo->tm_year + 1900; - to->month = timeInfo->tm_mon + 1; - to->day = timeInfo->tm_mday; - to->hour = timeInfo->tm_hour; - to->minute = timeInfo->tm_min; - to->second = timeInfo->tm_sec; + + to->year = time_tm.tm_year + 1900; + to->month = time_tm.tm_mon + 1; + to->day = time_tm.tm_mday; + to->hour = time_tm.tm_hour; + to->minute = time_tm.tm_min; + to->second = time_tm.tm_sec; to->usecond = from->tv_usec; return returnvalue::OK; } +ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* to) { + struct tm time_tm = {}; + + time_tm.tm_year = from->year - 1900; + time_tm.tm_mon = from->month - 1; + time_tm.tm_mday = from->day; + + time_tm.tm_hour = from->hour; + time_tm.tm_min = from->minute; + time_tm.tm_sec = from->second; + + time_tm.tm_isdst = 0; + +#ifdef PLATFORM_WIN + time_t seconds = _mkgmtime(&time_tm); +#else + time_t seconds = timegm(&time_tm); +#endif + + to->tv_sec = seconds; + 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; +} + ReturnValue_t Clock::checkOrCreateClockMutex() { if (timeMutex == nullptr) { MutexFactory* mutexFactory = MutexFactory::instance(); @@ -94,3 +121,37 @@ ReturnValue_t Clock::checkOrCreateClockMutex() { } return returnvalue::OK; } + +ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { + timeval time_timeval; + ReturnValue_t result = getClock_timeval(&time_timeval); + if (result != returnvalue::OK) { + return result; + } + return convertTimevalToTimeOfDay(&time_timeval, time); +} + +ReturnValue_t Clock::getClock_usecs(uint64_t* time) { + timeval timeVal{}; + ReturnValue_t result = getClock_timeval(&timeVal); + if (result != returnvalue::OK) { + return result; + } + *time = static_cast(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; +} \ No newline at end of file diff --git a/src/fsfw/timemanager/Stopwatch.cpp b/src/fsfw/timemanager/Stopwatch.cpp index 05d5c0e8b..0848bad43 100644 --- a/src/fsfw/timemanager/Stopwatch.cpp +++ b/src/fsfw/timemanager/Stopwatch.cpp @@ -9,10 +9,10 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode) : displayOnDestruction(displayOnDestruction), displayMode(displayMode) { // Measures start time on initialization. - Clock::getUptime(&startTime); + startTime = Clock::getUptime(); } -void Stopwatch::start() { Clock::getUptime(&startTime); } +void Stopwatch::start() { startTime = Clock::getUptime(); } dur_millis_t Stopwatch::stop(bool display) { stopInternal(); @@ -62,7 +62,6 @@ void Stopwatch::setDisplayMode(StopwatchDisplayMode displayMode) { StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; } void Stopwatch::stopInternal() { - timeval endTime; - Clock::getUptime(&endTime); + timeval endTime = Clock::getUptime(); elapsedTime = endTime - startTime; } diff --git a/unittests/osal/TestClock.cpp b/unittests/osal/TestClock.cpp index 5e381e8bf..b6d7261c6 100644 --- a/unittests/osal/TestClock.cpp +++ b/unittests/osal/TestClock.cpp @@ -24,14 +24,7 @@ TEST_CASE("OSAL::Clock Test", "[OSAL::Clock Test]") { // We require timeOfDayAsTimeval to be larger than time as it // was request a few ns later double difference = timevalOperations::toDouble(timeOfDayAsTimeval - time); - uint32_t ticksPerSecond =Clock:: getTicksPerSecond(); - float secondPerTick = 0; - if (ticksPerSecond != 0){ - secondPerTick = 1.0 / ticksPerSecond; - } - // In rtems, timevals have microsecond resolution, while TOD has only tick resolution, leading to - // negative differences when comparing "equal" times - CHECK(difference >= -secondPerTick); + CHECK(difference >= 0); CHECK(difference <= 0.005); // Conversion in the other direction From 7426e10f8270cc4988daf45c8bc1bcd3e72b0904 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Thu, 26 Jan 2023 11:33:40 +0100 Subject: [PATCH 21/21] clocks suck a little less --- src/fsfw/devicehandlers/DeviceHandlerBase.cpp | 11 ++- src/fsfw/osal/linux/Clock.cpp | 18 +---- src/fsfw/osal/rtems/Clock.cpp | 69 +++++-------------- src/fsfw/pus/Service9TimeManagement.cpp | 7 +- src/fsfw/subsystem/Subsystem.cpp | 5 +- src/fsfw/thermal/Heater.cpp | 5 +- src/fsfw/timemanager/ClockCommon.cpp | 28 ++++++-- src/fsfw/timemanager/Countdown.cpp | 8 +-- .../tmtcservices/CommandingServiceBase.cpp | 5 +- 9 files changed, 59 insertions(+), 97 deletions(-) diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index 60966501a..86df52c28 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -321,8 +321,7 @@ void DeviceHandlerBase::doStateMachine() { if (mode != currentMode) { break; } - uint32_t currentUptime; - Clock::getUptime(¤tUptime); + uint32_t currentUptime = Clock::getUptime_ms(); if (currentUptime - timeoutStart >= childTransitionDelay) { #if FSFW_VERBOSE_LEVEL >= 1 && FSFW_OBJ_EVENT_TRANSLATION == 0 char printout[60]; @@ -346,8 +345,7 @@ void DeviceHandlerBase::doStateMachine() { setMode(_MODE_WAIT_ON); break; case _MODE_WAIT_ON: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); + uint32_t currentUptime = Clock::getUptime_ms(); if (powerSwitcher != nullptr and currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0); @@ -366,8 +364,7 @@ void DeviceHandlerBase::doStateMachine() { } } break; case _MODE_WAIT_OFF: { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); + uint32_t currentUptime = Clock::getUptime_ms(); if (powerSwitcher == nullptr) { setMode(MODE_OFF); @@ -577,7 +574,7 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) { modeHelper.modeChanged(newMode, newSubmode); announceMode(false); } - Clock::getUptime(&timeoutStart); + timeoutStart = Clock::getUptime_ms(); if (mode == MODE_OFF and thermalSet != nullptr) { ReturnValue_t result = thermalSet->read(); diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index c7c92415b..c860e5df2 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -37,20 +37,8 @@ timeval Clock::getUptime() { timeval uptime{0,0}; double uptimeSeconds; if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) { - uptime->tv_sec = uptimeSeconds; - uptime->tv_usec = uptimeSeconds * (double)1e6 - (uptime->tv_sec * 1e6); + uptime.tv_sec = uptimeSeconds; + uptime.tv_usec = uptimeSeconds * (double)1e6 - (uptime.tv_sec * 1e6); } return 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; -//} - +} \ No newline at end of file diff --git a/src/fsfw/osal/rtems/Clock.cpp b/src/fsfw/osal/rtems/Clock.cpp index d5d61ef78..2cf903c84 100644 --- a/src/fsfw/osal/rtems/Clock.cpp +++ b/src/fsfw/osal/rtems/Clock.cpp @@ -6,20 +6,21 @@ #include "fsfw/ipc/MutexGuard.h" #include "fsfw/osal/rtems/RtemsBasic.h" -uint32_t Clock::getTicksPerSecond(void) { - rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); - return static_cast(ticks_per_second); -} -ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { +ReturnValue_t Clock::setClock(const timeval* time) { + TimeOfDay_t time_tod; + ReturnValue_t result = convertTimevalToTimeOfDay(time, &time_tod); + if (result != returnvalue::OK) { + return result; + } rtems_time_of_day timeRtems; - timeRtems.year = time->year; - timeRtems.month = time->month; - timeRtems.day = time->day; - timeRtems.hour = time->hour; - timeRtems.minute = time->minute; - timeRtems.second = time->second; - timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; + timeRtems.year = time_tod.year; + timeRtems.month = time_tod.month; + timeRtems.day = time_tod.day; + timeRtems.hour = time_tod.hour; + timeRtems.minute = time_tod.minute; + timeRtems.second = time_tod.second; + timeRtems.ticks = static_cast(time_tod.usecond) * rtems_clock_get_ticks_per_second() / 1e6; rtems_status_code status = rtems_clock_set(&timeRtems); switch (status) { case RTEMS_SUCCESSFUL: @@ -33,15 +34,6 @@ 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; - } - return setClock(&time_tod); -} - ReturnValue_t Clock::getClock_timeval(timeval* time) { // Callable from ISR rtems_status_code status = rtems_clock_get_tod_timeval(time); @@ -55,36 +47,13 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { } } -ReturnValue_t Clock::getUptime(timeval* uptime) { +timeval Clock::getUptime() { // According to docs.rtems.org for rtems 5 this method is more accurate than // rtems_clock_get_ticks_since_boot + timeval time_timeval; timespec time; rtems_status_code status = rtems_clock_get_uptime(&time); - uptime->tv_sec = time.tv_sec; - uptime->tv_usec = time.tv_nsec / 1000; - switch (status) { - case RTEMS_SUCCESSFUL: - return returnvalue::OK; - default: - return returnvalue::FAILED; - } -} - -ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { - // 32bit counter overflows after 50 days - uint64_t uptime = rtems_clock_get_uptime_nanoseconds() / 1e6; - *uptimeMs = uptime & 0xffffffff; - 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; - } -} + time_timeval.tv_sec = time.tv_sec; + time_timeval.tv_usec = time.tv_nsec / 1000; + return time_timeval; +} \ No newline at end of file diff --git a/src/fsfw/pus/Service9TimeManagement.cpp b/src/fsfw/pus/Service9TimeManagement.cpp index d19cb5182..0ea369f74 100644 --- a/src/fsfw/pus/Service9TimeManagement.cpp +++ b/src/fsfw/pus/Service9TimeManagement.cpp @@ -33,13 +33,12 @@ ReturnValue_t Service9TimeManagement::setTime() { return result; } - uint32_t formerUptime; - Clock::getUptime(&formerUptime); + // TODO maybe switch to getClock_usecs to report more meaningful data + uint32_t formerUptime = Clock::getUptime_ms(); result = Clock::setClock(&timeToSet); if (result == returnvalue::OK) { - uint32_t newUptime; - Clock::getUptime(&newUptime); + uint32_t newUptime = Clock::getUptime_ms(); triggerEvent(CLOCK_SET, newUptime, formerUptime); return returnvalue::OK; } else { diff --git a/src/fsfw/subsystem/Subsystem.cpp b/src/fsfw/subsystem/Subsystem.cpp index b2af5ac37..6624d86ec 100644 --- a/src/fsfw/subsystem/Subsystem.cpp +++ b/src/fsfw/subsystem/Subsystem.cpp @@ -91,11 +91,10 @@ void Subsystem::performChildOperation() { } if (currentSequenceIterator->getWaitSeconds() != 0) { if (uptimeStartTable == 0) { - Clock::getUptime(&uptimeStartTable); + uptimeStartTable = Clock::getUptime_ms(); return; } else { - uint32_t uptimeNow; - Clock::getUptime(&uptimeNow); + uint32_t uptimeNow = Clock::getUptime_ms(); if ((uptimeNow - uptimeStartTable) < (currentSequenceIterator->getWaitSeconds() * 1000)) { return; } diff --git a/src/fsfw/thermal/Heater.cpp b/src/fsfw/thermal/Heater.cpp index 64348106a..a37ae066c 100644 --- a/src/fsfw/thermal/Heater.cpp +++ b/src/fsfw/thermal/Heater.cpp @@ -198,10 +198,9 @@ void Heater::setSwitch(uint8_t number, ReturnValue_t state, uint32_t* uptimeOfSw } else { if ((*uptimeOfSwitching == INVALID_UPTIME)) { powerSwitcher->sendSwitchCommand(number, state); - Clock::getUptime(uptimeOfSwitching); + *uptimeOfSwitching = Clock::getUptime_ms(); } else { - uint32_t currentUptime; - Clock::getUptime(¤tUptime); + uint32_t currentUptime = Clock::getUptime_ms(); if (currentUptime - *uptimeOfSwitching > powerSwitcher->getSwitchDelayMs()) { *uptimeOfSwitching = INVALID_UPTIME; if (healthHelper.healthTable->isHealthy(getObjectId())) { diff --git a/src/fsfw/timemanager/ClockCommon.cpp b/src/fsfw/timemanager/ClockCommon.cpp index a35848277..d5f9c2f83 100644 --- a/src/fsfw/timemanager/ClockCommon.cpp +++ b/src/fsfw/timemanager/ClockCommon.cpp @@ -1,4 +1,5 @@ #include +#include #include "fsfw/ipc/MutexGuard.h" #include "fsfw/timemanager/Clock.h" @@ -91,15 +92,28 @@ ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, timeval* time_tm.tm_isdst = 0; -#ifdef PLATFORM_WIN - time_t seconds = _mkgmtime(&time_tm); -#else - time_t seconds = timegm(&time_tm); -#endif - + // 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; } @@ -152,6 +166,6 @@ ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { } uint32_t Clock::getUptime_ms() { timeval uptime = getUptime(); - //TODO verify that overflow is correct + // TODO verify that overflow is correct return uptime.tv_sec * 1e3 + uptime.tv_usec / 1e3; } \ No newline at end of file diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp index a8ba78cbb..9f0152a9e 100644 --- a/src/fsfw/timemanager/Countdown.cpp +++ b/src/fsfw/timemanager/Countdown.cpp @@ -7,9 +7,9 @@ Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) { Countdown::~Countdown() {} ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { - ReturnValue_t returnValue = Clock::getUptime(&startTime); + startTime = Clock::getUptime_ms(); timeout = milliseconds; - return returnValue; + return returnvalue::OK; } bool Countdown::hasTimedOut() const { @@ -39,7 +39,5 @@ uint32_t Countdown::getRemainingMillis() const { } uint32_t Countdown::getCurrentTime() const { - uint32_t currentTime; - Clock::getUptime(¤tTime); - return currentTime; + return Clock::getUptime_ms(); } diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp index 1ec5c0d81..59addbdfa 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -348,7 +348,7 @@ void CommandingServiceBase::startExecution(store_address_t storeId, CommandMapIt sendResult = commandQueue->sendMessage(iter.value->first, &command); } if (sendResult == returnvalue::OK) { - Clock::getUptime(&iter->second.uptimeOfStart); + iter->second.uptimeOfStart = Clock::getUptime_ms(); iter->second.step = 0; iter->second.subservice = tcReader.getSubService(); iter->second.command = command.getCommand(); @@ -434,8 +434,7 @@ inline void CommandingServiceBase::doPeriodicOperation() {} MessageQueueId_t CommandingServiceBase::getCommandQueue() { return commandQueue->getId(); } void CommandingServiceBase::checkTimeout() { - uint32_t uptime; - Clock::getUptime(&uptime); + uint32_t uptime = Clock::getUptime_ms(); CommandMapIter iter; for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {