From e26f0d54b2828e786c4d91ef38345a7e68d1fbcf Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:44:03 +0200 Subject: [PATCH 1/6] binary semaphore init --- osal/FreeRTOS/BinarySemaphore.cpp | 152 ++++++++++++++++++++++++++++++ osal/FreeRTOS/BinarySemaphore.h | 130 +++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 osal/FreeRTOS/BinarySemaphore.cpp create mode 100644 osal/FreeRTOS/BinarySemaphore.h diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp new file mode 100644 index 000000000..b5f8e6c6c --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -0,0 +1,152 @@ +/** + * @file BinarySemaphore.cpp + * + * @date 25.02.2020 + */ +#include +#include + +#include + +extern "C" { +#include "portmacro.h" +#include "task.h" +} + +BinarySemaphore::BinarySemaphore() { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore::~BinarySemaphore() { + vSemaphoreDelete(handle); +} + +// This copy ctor is important as it prevents the assignment to a ressource +// (other.handle) variable which is later deleted! +BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { + if(this != &s) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } + } + return *this; +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + if(&s != this) { + xSemaphoreCreateBinary(handle); + if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; + } + } + return *this; +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { + if(handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; + if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { + timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; + } + else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + + BaseType_t returncode = xSemaphoreTake(handle, timeout); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( + TickType_t timeoutTicks) { + if(handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + + BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { + if (handle == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGive(handle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} + +SemaphoreHandle_t BinarySemaphore::getSemaphore() { + return handle; +} + +ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGive(semaphore); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } else { + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +void BinarySemaphore::resetSemaphore() { + if(handle != nullptr) { + vSemaphoreDelete(handle); + xSemaphoreCreateBinary(handle); + } +} + + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken) { + if (semaphore == nullptr) { + return SEMAPHORE_NULLPOINTER; + } + BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + if (returncode == pdPASS) { + if(*higherPriorityTaskWoken == pdPASS) { + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. + TaskManagement::requestContextSwitch(CallContext::isr); + } + return HasReturnvaluesIF::RETURN_OK; + } else { + return SEMAPHORE_NOT_OWNED; + } +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h new file mode 100644 index 000000000..2203c923a --- /dev/null +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -0,0 +1,130 @@ +/** + * @file BinarySempahore.h + * + * @date 25.02.2020 + */ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ + +#include + +extern "C" { +#include "FreeRTOS.h" +#include "semphr.h" +} + + +/** + * @brief OS Tool to achieve synchronization of between tasks or between task and ISR + * @details + * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * @ingroup osal + */ +class BinarySemaphore: public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! No block time, poll the semaphore. Can also be used as tick type. + //! Can be passed as tick type and ms value. + static constexpr uint32_t NO_BLOCK_TIMEOUT = 0; + static constexpr TickType_t NO_BLOCK_TICKS = 0; + //! No block time, poll the semaphore. + //! Can be passed as tick type and ms value. + static constexpr TickType_t BLOCK_TIMEOUT_TICKS = portMAX_DELAY; + static constexpr uint32_t BLOCK_TIMEOUT = portMAX_DELAY; + + //! Semaphore timeout + static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); + /** The current semaphore can not be given, because it is not owned */ + static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); + + BinarySemaphore(); + + /** + * @brief Copy ctor + */ + BinarySemaphore(const BinarySemaphore&); + + /** + * @brief Copy assignment + */ + BinarySemaphore& operator=(const BinarySemaphore&); + + /** + * @brief Move constructor + */ + BinarySemaphore (BinarySemaphore &&); + + /** + * Move assignment + */ + BinarySemaphore & operator=(BinarySemaphore &&); + + /** + * Delete the binary semaphore to prevent a memory leak + */ + virtual ~BinarySemaphore(); + + /** + * Take the binary semaphore. + * If the semaphore has already been taken, the task will be blocked for a maximum + * of #timeoutMs or until the semaphore is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = + BinarySemaphore::NO_BLOCK_TIMEOUT); + + /** + * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = + BinarySemaphore::NO_BLOCK_TICKS); + + /** + * Give back the binary semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t giveBinarySemaphore(); + + /** + * Get Handle to the semaphore. + * @return + */ + SemaphoreHandle_t getSemaphore(); + + /** + * Reset the semaphore. + */ + void resetSemaphore(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); + + /** + * Wrapper function to give back semaphore from handle when called from an ISR + * @param semaphore + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority + * was unblocked + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + BaseType_t * higherPriorityTaskWoken); +private: + SemaphoreHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ -- 2.34.1 From 6eda5a08381891907d67e3b23a93e80808585b07 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:46:49 +0200 Subject: [PATCH 2/6] task management header added --- osal/FreeRTOS/TaskManagement.h | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osal/FreeRTOS/TaskManagement.h diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h new file mode 100644 index 000000000..fd2bfc0b1 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.h @@ -0,0 +1,38 @@ +/** + * @file TaskManagement.h + * + * @date 26.02.2020 + */ + +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +/*! + * Used by functions to tell if they are being called from + * within an ISR or from a regular task. This is required because FreeRTOS + * has different functions for handling semaphores and messages from within an ISR and task. + */ + +enum CallContext { + task = 0x00,//!< task_context + isr = 0xFF //!< isr_context +}; + +class TaskManagement { +public: + /** + * In this function, a function dependant on the portmacro.h header function calls + * to request a context switch can be specified. + * This can be used if sending to the queue from an ISR caused a task to unblock + * and a context switch is required. + */ + static void requestContextSwitch(CallContext callContext); + + /** + * If task preemption in FreeRTOS is disabled, a context switch + * can be requested manually by calling this function. + */ + static void requestContextSwitchFromTask(void); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ -- 2.34.1 From 1b5127dc85f236d7e02cdb22c722bea4976d531b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:50:07 +0200 Subject: [PATCH 3/6] added task management implementation --- osal/FreeRTOS/TaskManagement.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osal/FreeRTOS/TaskManagement.cpp diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp new file mode 100644 index 000000000..9946833d2 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -0,0 +1,32 @@ +/** + * @file TaskManagement.cpp + * + * @date 26.02.2020 + * + */ +#include +#include +#include "portmacro.h" +#include "task.h" + +/** + * TODO: This stuff is hardware and architecture and mission dependant... + * Some FreeRTOS implementations might be able to determine their own task context for example. + * If not ISRs are used, or task preemption is enabled, some of this stuff might + * not be necessary anyway. Maybe there is a better solution? + */ +void TaskManagement::requestContextSwitchFromTask() { + 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 + portYIELD_FROM_ISR(); + } else { + requestContextSwitchFromTask(); + } +} + + + -- 2.34.1 From 0e6f8d3f821d3fa6907de2310e9102a33d30afb2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:53:06 +0200 Subject: [PATCH 4/6] comment adapted --- osal/FreeRTOS/TaskManagement.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 9946833d2..0c96c62f0 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -5,15 +5,17 @@ * */ #include -#include + +extern "C" { +#include "FreeRTOS.h" #include "portmacro.h" #include "task.h" +} /** * TODO: This stuff is hardware and architecture and mission dependant... - * Some FreeRTOS implementations might be able to determine their own task context for example. - * If not ISRs are used, or task preemption is enabled, some of this stuff might - * not be necessary anyway. Maybe there is a better solution? + * Maybe there is a better solution? The request ContextSwitch function + * could be declared external for example. */ void TaskManagement::requestContextSwitchFromTask() { vTaskDelay(0); -- 2.34.1 From 328737d0ad5d6efb098963fdf0e5088776f50f64 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:12:02 +0200 Subject: [PATCH 5/6] newer non-deprecated semaphore call used --- osal/FreeRTOS/BinarySemaphore.cpp | 24 +++++++++++++----------- osal/FreeRTOS/BinarySemaphore.h | 8 ++++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index b5f8e6c6c..a6a923aaf 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -8,16 +8,13 @@ #include -extern "C" { -#include "portmacro.h" -#include "task.h" -} - BinarySemaphore::BinarySemaphore() { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { + error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore::~BinarySemaphore() { @@ -27,36 +24,40 @@ BinarySemaphore::~BinarySemaphore() { // This copy ctor is important as it prevents the assignment to a ressource // (other.handle) variable which is later deleted! BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } return *this; } BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } BinarySemaphore& BinarySemaphore::operator =( BinarySemaphore&& s) { if(&s != this) { - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); if(handle == nullptr) { error << "Binary semaphore creation failure" << std::endl; } + xSemaphoreGive(handle); } return *this; } @@ -127,7 +128,8 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) void BinarySemaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); - xSemaphoreCreateBinary(handle); + handle = xSemaphoreCreateBinary(); + xSemaphoreGive(handle); } } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 2203c923a..0ab9cdea6 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -18,6 +18,10 @@ extern "C" { * @brief OS Tool to achieve synchronization of between tasks or between task and ISR * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html + * + * SHOULDDO: check freeRTOS version and use new task notifications, + * if non-ancient freeRTOS version is used. + * * @ingroup osal */ class BinarySemaphore: public HasReturnvaluesIF { @@ -68,8 +72,8 @@ public: /** * Take the binary semaphore. - * If the semaphore has already been taken, the task will be blocked for a maximum - * of #timeoutMs or until the semaphore is given back, + * If the semaphore has already been taken, the task will be blocked + * for a maximum of #timeoutMs or until the semaphore is given back, * for example by an ISR or another task. * @param timeoutMs * @return -@c RETURN_OK on success -- 2.34.1 From fc4199c3b12dfc6f7996d75c035fb0767c21a004 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:13:14 +0200 Subject: [PATCH 6/6] architecture dependant call delcared external --- osal/FreeRTOS/TaskManagement.cpp | 8 +------- osal/FreeRTOS/TaskManagement.h | 7 +++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 0c96c62f0..d7ddaf384 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -8,15 +8,9 @@ extern "C" { #include "FreeRTOS.h" -#include "portmacro.h" #include "task.h" } -/** - * TODO: This stuff is hardware and architecture and mission dependant... - * Maybe there is a better solution? The request ContextSwitch function - * could be declared external for example. - */ void TaskManagement::requestContextSwitchFromTask() { vTaskDelay(0); } @@ -24,7 +18,7 @@ void TaskManagement::requestContextSwitchFromTask() { void TaskManagement::requestContextSwitch(CallContext callContext = CallContext::task) { if(callContext == CallContext::isr) { // This function depends on the partmacro.h definition for the specific device - portYIELD_FROM_ISR(); + requestContextSwitchFromISR(); } else { requestContextSwitchFromTask(); } diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index fd2bfc0b1..c122e0fba 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -7,6 +7,12 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ #define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +/** + * Architecture dependant portmacro.h function call. + * Should be implemented in bsp. + */ +extern "C" void requestContextSwitchFromISR(); + /*! * Used by functions to tell if they are being called from * within an ISR or from a regular task. This is required because FreeRTOS @@ -18,6 +24,7 @@ enum CallContext { isr = 0xFF //!< isr_context }; + class TaskManagement { public: /** -- 2.34.1