From e26f0d54b2828e786c4d91ef38345a7e68d1fbcf Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:44:03 +0200 Subject: [PATCH 01/22] 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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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 From 1d4d01d1906d1300eb7fe4e65d259afe64210a81 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:22:10 +0200 Subject: [PATCH 07/22] Added ISR calls for MQ and task mgmt The task management defines an external function which implements a context switch call from an ISR --- osal/FreeRTOS/MessageQueue.cpp | 95 ++++++++++++++++++++------------ osal/FreeRTOS/MessageQueue.h | 75 +++++++++++++++++-------- osal/FreeRTOS/TaskManagement.cpp | 24 ++++++++ osal/FreeRTOS/TaskManagement.h | 63 +++++++++++++++++++++ 4 files changed, 199 insertions(+), 58 deletions(-) create mode 100644 osal/FreeRTOS/TaskManagement.cpp create mode 100644 osal/FreeRTOS/TaskManagement.h diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index e5da04427..38f425a4f 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -2,11 +2,14 @@ #include -// TODO I guess we should have a way of checking if we are in an ISR and then use the "fromISR" versions of all calls - -MessageQueue::MessageQueue(size_t message_depth, size_t max_message_size) : -defaultDestination(0),lastPartner(0) { - handle = xQueueCreate(message_depth, max_message_size); +// TODO I guess we should have a way of checking if we are in an ISR and then +// use the "fromISR" versions of all calls +// As a first step towards this, introduces system context variable which needs +// to be switched manually +// Haven't found function to find system context. +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) : +defaultDestination(0),lastPartner(0), callContext(CallContext::task) { + handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == NULL) { sif::error << "MessageQueue creation failed" << std::endl; } @@ -18,6 +21,10 @@ MessageQueue::~MessageQueue() { } } +void MessageQueue::switchSystemContext(CallContext callContext) { + this->callContext = callContext; +} + ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, MessageQueueMessage* message, bool ignoreFault) { return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); @@ -27,6 +34,11 @@ ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessage* message) { return sendToDefaultFrom(message, this->getId()); } +ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, + MessageQueueId_t sentFrom, bool ignoreFault) { + return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); +} + ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { if (this->lastPartner != 0) { return sendMessageFrom(this->lastPartner, message, this->getId()); @@ -35,6 +47,27 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { } } +ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom, + bool ignoreFault) { + return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault, callContext); +} + + +ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { + if (result != pdPASS) { + if (!ignoreFault) { + InternalErrorReporterIF* internalErrorReporter = objectManager->get( + objects::INTERNAL_ERROR_REPORTER); + if (internalErrorReporter != NULL) { + internalErrorReporter->queueMessageNotSent(); + } + } + return MessageQueueIF::FULL; + } + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, MessageQueueId_t* receivedFrom) { ReturnValue_t status = this->receiveMessage(message); @@ -73,17 +106,6 @@ void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { this->defaultDestination = defaultDestination; } -ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, - MessageQueueMessage* message, MessageQueueId_t sentFrom, - bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault); -} - -ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessage* message, - MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); -} - MessageQueueId_t MessageQueue::getDefaultDestination() const { return defaultDestination; } @@ -92,23 +114,28 @@ bool MessageQueue::isDefaultDestinationSet() const { return 0; } + +// static core function to send messages. ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, - MessageQueueMessage *message, MessageQueueId_t sentFrom, - bool ignoreFault) { - message->setSender(sentFrom); - - BaseType_t result = xQueueSendToBack(reinterpret_cast(sendTo),reinterpret_cast(message->getBuffer()), 0); - if (result != pdPASS) { - if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( - objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { - internalErrorReporter->queueMessageNotSent(); - } - } - return MessageQueueIF::FULL; - } - return HasReturnvaluesIF::RETURN_OK; - + MessageQueueMessage *message, MessageQueueId_t sentFrom, + bool ignoreFault, CallContext callContext) { + message->setSender(sentFrom); + BaseType_t result; + if(callContext == CallContext::task) { + result = xQueueSendToBack(reinterpret_cast(sendTo), + static_cast(message->getBuffer()), 0); + } + else { + // If the call context is from an interrupt, + // request a context switch if a higher priority task + // was blocked by the interrupt. + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + result = xQueueSendFromISR(reinterpret_cast(sendTo), + static_cast(message->getBuffer()), + &xHigherPriorityTaskWoken); + if(xHigherPriorityTaskWoken == pdTRUE) { + TaskManagement::requestContextSwitch(callContext); + } + } + return handleSendResult(result, ignoreFault); } - diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 32f41b44d..ce6ed46b3 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -4,9 +4,14 @@ #include #include #include +#include + +extern "C" { +#include +#include +} + -#include -#include //TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ @@ -21,11 +26,17 @@ * methods to send a message to a user-defined or a default destination. In addition * it also provides a reply method to answer to the queue it received its last message * from. + * * The MessageQueue should be used as "post box" for a single owning object. So all * message queue communication is "n-to-one". * For creating the queue, as well as sending and receiving messages, the class makes * use of the operating system calls provided. - * \ingroup message_queue + * + * Please keep in mind that FreeRTOS offers + * different calls for message queue operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue */ class MessageQueue : public MessageQueueIF { friend class MessageQueueSenderIF; @@ -43,11 +54,15 @@ public: * This should be left default. */ MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + /** * @brief The destructor deletes the formerly created message queue. * @details This is accomplished by using the delete call provided by the operating system. */ virtual ~MessageQueue(); + + void switchSystemContext(CallContext callContext); + /** * @brief This operation sends a message to the given destination. * @details It directly uses the sendMessage call of the MessageQueueSender parent, but passes its @@ -74,6 +89,29 @@ public: */ ReturnValue_t reply( MessageQueueMessage* message ); + /** + * \brief With the sendMessage call, a queue message is sent to a receiving queue. + * \details This method takes the message provided, adds the sentFrom information and passes + * it on to the destination provided with an operating system call. The OS's return + * value is returned. + * \param sendTo This parameter specifies the message queue id to send the message to. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + */ + virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, + MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + + /** + * \brief The sendToDefault method sends a queue message to the default destination. + * \details In all other aspects, it works identical to the sendMessage method. + * \param message This is a pointer to a previously created message, which is sent. + * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * This variable is set to zero by default. + */ + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * @brief This function reads available messages from the message queue and returns the sender. * @details It works identically to the other receiveMessage call, but in addition returns the @@ -107,26 +145,7 @@ public: * @brief This method returns the message queue id of this class's message queue. */ MessageQueueId_t getId() const; - /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - */ - virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); - /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + /** * \brief This method is a simple setter for the default destination. */ @@ -148,12 +167,20 @@ protected: * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + * \param context */ - static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,bool ignoreFault=false); + static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, + MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, + bool ignoreFault=false, CallContext callContext = CallContext::task); + + static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); + + private: QueueHandle_t handle; MessageQueueId_t defaultDestination; MessageQueueId_t lastPartner; + CallContext callContext; //!< Stores the current system context }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp new file mode 100644 index 000000000..522225319 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -0,0 +1,24 @@ +#include + +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 + requestContextSwitchFromISR(); + } else { + requestContextSwitchFromTask(); + } +} + +TaskHandle_t TaskManagement::getCurrentTaskHandle() { + return xTaskGetCurrentTaskHandle(); +} + +configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() { + return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle()); +} + + diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h new file mode 100644 index 000000000..eaaf97e22 --- /dev/null +++ b/osal/FreeRTOS/TaskManagement.h @@ -0,0 +1,63 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ +#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ + +#include + +extern "C" { +#include +#include +} +#include + +/** + * 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 + * 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); + + /** + * @return The current task handle + */ + static TaskHandle_t getCurrentTaskHandle(); + + /** + * Get returns the minimum amount of remaining stack space in words + * that was a available to the task since the task started executing. + * Please note that the actual value in bytes depends + * on the stack depth type. + * E.g. on a 32 bit machine, a value of 200 means 800 bytes. + * @return Smallest value of stack remaining since the task was started in + * words. + */ + static configSTACK_DEPTH_TYPE getTaskStackHighWatermark(); +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */ -- 2.34.1 From d1500a78685d18e05b94419be69f9cb09056c127 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:31:05 +0200 Subject: [PATCH 08/22] mq doc improvements --- osal/FreeRTOS/MessageQueue.cpp | 9 ++- osal/FreeRTOS/MessageQueue.h | 120 ++++++++++++++++++--------------- 2 files changed, 72 insertions(+), 57 deletions(-) diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 38f425a4f..12a3173ad 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -50,14 +50,16 @@ ReturnValue_t MessageQueue::reply(MessageQueueMessage* message) { ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom, bool ignoreFault) { - return sendMessageFromMessageQueue(sendTo,message,sentFrom,ignoreFault, callContext); + return sendMessageFromMessageQueue(sendTo, message, sentFrom, + ignoreFault, callContext); } ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { if (result != pdPASS) { if (!ignoreFault) { - InternalErrorReporterIF* internalErrorReporter = objectManager->get( + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != NULL) { internalErrorReporter->queueMessageNotSent(); @@ -78,7 +80,8 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message, } ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { - BaseType_t result = xQueueReceive(handle,reinterpret_cast(message->getBuffer()), 0); + BaseType_t result = xQueueReceive(handle,reinterpret_cast( + message->getBuffer()), 0); if (result == pdPASS){ this->lastPartner = message->getSender(); return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index ce6ed46b3..c278e3296 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -12,52 +12,57 @@ extern "C" { } - //TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ /** - * @brief This class manages sending and receiving of message queue messages. + * @brief This class manages sending and receiving of + * message queue messages. + * @details + * Message queues are used to pass asynchronous messages between processes. + * They work like post boxes, where all incoming messages are stored in FIFO + * order. This class creates a new receiving queue and provides methods to fetch + * received messages. Being a child of MessageQueueSender, this class also + * provides methods to send a message to a user-defined or a default destination. + * In addition it also provides a reply method to answer to the queue it + * received its last message from. * - * @details Message queues are used to pass asynchronous messages between processes. - * They work like post boxes, where all incoming messages are stored in FIFO - * order. This class creates a new receiving queue and provides methods to fetch - * received messages. Being a child of MessageQueueSender, this class also provides - * methods to send a message to a user-defined or a default destination. In addition - * it also provides a reply method to answer to the queue it received its last message - * from. + * The MessageQueue should be used as "post box" for a single owning object. + * So all message queue communication is "n-to-one". + * For creating the queue, as well as sending and receiving messages, the class + * makes use of the operating system calls provided. * - * The MessageQueue should be used as "post box" for a single owning object. So all - * message queue communication is "n-to-one". - * For creating the queue, as well as sending and receiving messages, the class makes - * use of the operating system calls provided. - * - * Please keep in mind that FreeRTOS offers - * different calls for message queue operations if called from an ISR. - * For now, the system context needs to be switched manually. - * @ingroup osal - * @ingroup message_queue + * Please keep in mind that FreeRTOS offers different calls for message queue + * operations if called from an ISR. + * For now, the system context needs to be switched manually. + * @ingroup osal + * @ingroup message_queue */ class MessageQueue : public MessageQueueIF { friend class MessageQueueSenderIF; public: /** * @brief The constructor initializes and configures the message queue. - * @details By making use of the according operating system call, a message queue is created - * and initialized. The message depth - the maximum number of messages to be - * buffered - may be set with the help of a parameter, whereas the message size is - * automatically set to the maximum message queue message size. The operating system - * sets the message queue id, or i case of failure, it is set to zero. - * @param message_depth The number of messages to be buffered before passing an error to the - * sender. Default is three. - * @param max_message_size With this parameter, the maximum message size can be adjusted. - * This should be left default. + * @details + * By making use of the according operating system call, a message queue is created + * and initialized. The message depth - the maximum number of messages to be + * buffered - may be set with the help of a parameter, whereas the message size is + * automatically set to the maximum message queue message size. The operating system + * sets the message queue id, or i case of failure, it is set to zero. + * @param message_depth + * The number of messages to be buffered before passing an error to the + * sender. Default is three. + * @param max_message_size + * With this parameter, the maximum message size can be adjusted. + * This should be left default. */ - MessageQueue( size_t message_depth = 3, size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + MessageQueue( size_t message_depth = 3, + size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); /** * @brief The destructor deletes the formerly created message queue. - * @details This is accomplished by using the delete call provided by the operating system. + * @details This is accomplished by using the delete call provided + * by the operating system. */ virtual ~MessageQueue(); @@ -90,27 +95,28 @@ public: ReturnValue_t reply( MessageQueueMessage* message ); /** - * \brief With the sendMessage call, a queue message is sent to a receiving queue. - * \details This method takes the message provided, adds the sentFrom information and passes + * @brief With the sendMessage call, a queue message is sent to a receiving queue. + * @details This method takes the message provided, adds the sentFrom information and passes * it on to the destination provided with an operating system call. The OS's return * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * @param sendTo This parameter specifies the message queue id to send the message to. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. + * @param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. */ virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** - * \brief The sendToDefault method sends a queue message to the default destination. - * \details In all other aspects, it works identical to the sendMessage method. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. + * @brief The sendToDefault method sends a queue message to the default destination. + * @details In all other aspects, it works identical to the sendMessage method. + * @param message This is a pointer to a previously created message, which is sent. + * @param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. * This variable is set to zero by default. */ - virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); + virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message, + MessageQueueId_t sentFrom = NO_QUEUE, bool ignoreFault = false ); /** * @brief This function reads available messages from the message queue and returns the sender. @@ -147,27 +153,34 @@ public: MessageQueueId_t getId() const; /** - * \brief This method is a simple setter for the default destination. + * @brief This method is a simple setter for the default destination. */ void setDefaultDestination(MessageQueueId_t defaultDestination); /** - * \brief This method is a simple getter for the default destination. + * @brief This method is a simple getter for the default destination. */ MessageQueueId_t getDefaultDestination() const; bool isDefaultDestinationSet() const; protected: /** - * Implementation to be called from any send Call within MessageQueue and MessageQueueSenderIF - * \details This method takes the message provided, adds the sentFrom information and passes - * it on to the destination provided with an operating system call. The OS's return - * value is returned. - * \param sendTo This parameter specifies the message queue id to send the message to. - * \param message This is a pointer to a previously created message, which is sent. - * \param sentFrom The sentFrom information can be set to inject the sender's queue id into the message. - * This variable is set to zero by default. - * \param ignoreFault If set to true, the internal software fault counter is not incremented if queue is full. - * \param context + * @brief Implementation to be called from any send Call within + * MessageQueue and MessageQueueSenderIF. + * @details + * This method takes the message provided, adds the sentFrom information and + * passes it on to the destination provided with an operating system call. + * The OS's return value is returned. + * @param sendTo + * This parameter specifies the message queue id to send the message to. + * @param message + * This is a pointer to a previously created message, which is sent. + * @param sentFrom + * The sentFrom information can be set to inject the sender's queue id into + * the message. This variable is set to zero by default. + * @param ignoreFault + * If set to true, the internal software fault counter is not incremented + * if queue is full. + * @param context Specify whether call is made from task or from an ISR. */ static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, @@ -175,7 +188,6 @@ protected: static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); - private: QueueHandle_t handle; MessageQueueId_t defaultDestination; -- 2.34.1 From f8614e23a867d21d64922329164920c41ab55c38 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:38:19 +0200 Subject: [PATCH 09/22] deleted copy ans assignment ctor --- osal/FreeRTOS/MessageQueue.cpp | 18 +++++++++--------- osal/FreeRTOS/MessageQueue.h | 16 +++++++++++----- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 12a3173ad..9e4b581be 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -7,11 +7,10 @@ // As a first step towards this, introduces system context variable which needs // to be switched manually // Haven't found function to find system context. -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) : -defaultDestination(0),lastPartner(0), callContext(CallContext::task) { +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) { handle = xQueueCreate(messageDepth, maxMessageSize); if (handle == NULL) { - sif::error << "MessageQueue creation failed" << std::endl; + sif::error << "MessageQueue: Creation failed" << std::endl; } } @@ -57,11 +56,11 @@ ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::handleSendResult(BaseType_t result, bool ignoreFault) { if (result != pdPASS) { - if (!ignoreFault) { + if (not ignoreFault) { InternalErrorReporterIF* internalErrorReporter = objectManager->get( objects::INTERNAL_ERROR_REPORTER); - if (internalErrorReporter != NULL) { + if (internalErrorReporter != nullptr) { internalErrorReporter->queueMessageNotSent(); } } @@ -106,6 +105,7 @@ MessageQueueId_t MessageQueue::getId() const { } void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { + defaultDestinationSet = true; this->defaultDestination = defaultDestination; } @@ -114,7 +114,7 @@ MessageQueueId_t MessageQueue::getDefaultDestination() const { } bool MessageQueue::isDefaultDestinationSet() const { - return 0; + return defaultDestinationSet; } @@ -129,9 +129,9 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, static_cast(message->getBuffer()), 0); } else { - // If the call context is from an interrupt, - // request a context switch if a higher priority task - // was blocked by the interrupt. + /* If the call context is from an interrupt, + * request a context switch if a higher priority task + * was blocked by the interrupt. */ BaseType_t xHigherPriorityTaskWoken = pdFALSE; result = xQueueSendFromISR(reinterpret_cast(sendTo), static_cast(message->getBuffer()), diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index c278e3296..e88bbcec5 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -56,8 +56,12 @@ public: * With this parameter, the maximum message size can be adjusted. * This should be left default. */ - MessageQueue( size_t message_depth = 3, - size_t max_message_size = MessageQueueMessage::MAX_MESSAGE_SIZE ); + MessageQueue( size_t messageDepth = 3, + size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE ); + + /** Copying message queues forbidden */ + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; /** * @brief The destructor deletes the formerly created message queue. @@ -189,10 +193,12 @@ protected: static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); private: + bool defaultDestinationSet = false; QueueHandle_t handle; - MessageQueueId_t defaultDestination; - MessageQueueId_t lastPartner; - CallContext callContext; //!< Stores the current system context + MessageQueueId_t defaultDestination = 0; + MessageQueueId_t lastPartner = 0; + //!< Stores the current system context + CallContext callContext = CallContext::task; }; #endif /* MESSAGEQUEUE_H_ */ -- 2.34.1 From 41c0ca6c52a728ffaf359805efb0df0319b9dcc3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:39:10 +0200 Subject: [PATCH 10/22] added doc for switchSystemContext --- osal/FreeRTOS/MessageQueue.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index e88bbcec5..07e95ddf5 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -70,6 +70,11 @@ public: */ virtual ~MessageQueue(); + /** + * This function is used to switch the call context. This has to be called + * if a message is sent or received from an ISR! + * @param callContext + */ void switchSystemContext(CallContext callContext); /** -- 2.34.1 From b23728731548d900b97a70e3d32565ebcfcc50e7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:48:16 +0200 Subject: [PATCH 11/22] bin semaph sif replacements --- osal/FreeRTOS/BinarySemaphore.cpp | 11 +++++------ returnvalues/FwClassIds.h | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index a6a923aaf..acfc53bdd 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -11,8 +11,7 @@ BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -26,7 +25,7 @@ BinarySemaphore::~BinarySemaphore() { BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -35,7 +34,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -45,7 +44,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -55,7 +54,7 @@ BinarySemaphore& BinarySemaphore::operator =( if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - error << "Binary semaphore creation failure" << std::endl; + sif::error << "Binary semaphore creation failure" << std::endl; } xSemaphoreGive(handle); } diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index d21861c08..120d8b8c9 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -24,6 +24,7 @@ enum { MEMORY_HELPER, //MH SERIALIZE_IF, //SE FIXED_MAP, //FM + FIXED_MULTIMAP, //FMM HAS_HEALTH_IF, //HHI FIFO_CLASS, //FF MESSAGE_PROXY, //MQP @@ -59,6 +60,7 @@ enum { SGP4PROPAGATOR_CLASS, //SGP4 53 MUTEX_IF, //MUX 54 MESSAGE_QUEUE_IF,//MQI 55 + SEMAPHORE_IF, //SPH 56 FW_CLASS_ID_COUNT //is actually count + 1 ! }; -- 2.34.1 From 45b0193ef38b70a4f1d5be76564258bc6ab5c928 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 18:06:40 +0200 Subject: [PATCH 12/22] bin semaph todo --- osal/FreeRTOS/BinarySemaphore.h | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 0ab9cdea6..865da8a61 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,27 +1,24 @@ -/** - * @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" +#include +#include } - +// TODO: Counting semaphores and implement the new (better) +// task notifications. However, those use task notifications require +// the task handle. Maybe it would be better to make a separate class +// and switch between the classes with #ifdefs. +// Task Notifications require FreeRTOS V8.2 something.. /** * @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. - * + * @author R. Mueller * @ingroup osal */ class BinarySemaphore: public HasReturnvaluesIF { -- 2.34.1 From 87bf843beffe92f7f535609cb83fcb4378f952be Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:19:50 +0200 Subject: [PATCH 13/22] binary semaphore IF init --- tasks/SemaphoreIF.h | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tasks/SemaphoreIF.h diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h new file mode 100644 index 000000000..babac05a3 --- /dev/null +++ b/tasks/SemaphoreIF.h @@ -0,0 +1,8 @@ +#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#define FRAMEWORK_TASKS_SEMAPHOREIF_H_ + + + + + +#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ -- 2.34.1 From 9ba21b1e288ba9f8e20fae9c4cc7ea6923b2651f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:30:50 +0200 Subject: [PATCH 14/22] semaphore if continued --- tasks/SemaphoreIF.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index babac05a3..cf56f6f90 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -1,8 +1,49 @@ #ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_ #define FRAMEWORK_TASKS_SEMAPHOREIF_H_ +#include +#include +#include +/** + * @brief Generic interface for semaphores, which can be used to achieve + * task synchronization. + */ +class SemaphoreIF { + //!< Needs to be defined in implementation. + static const uint32_t NO_TIMEOUT; + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + //! 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); + /** + * Generic call to acquire a semaphore. + * If there are no more semaphores to be taken (for a counting semaphore, + * a semaphore may be taken more than once), the taks will block + * for a maximum of timeoutMs while trying to acquire the semaphore. + * This can be used to achieve task synchrnization. + * @param timeoutMs + * @return + */ + ReturnValue_t acquire(uint32_t timeoutMs) = 0; + /** + * Corrensponding call to release a semaphore. + * @return + */ + ReturnValue_t release() = 0; + + /** + * If the semaphore is a counting semaphore then the semaphores current + * count value is returned. If the semaphore is a binary semaphore then 1 + * is returned if the semaphore is available, and 0 is returned if the + * semaphore is not available. + * @return + */ + uint8_t getSemaphoreCounter() = 0; +}; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ -- 2.34.1 From 4dd6594845deb381b80fcb2ba8e0ec27acec27e1 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:38:02 +0200 Subject: [PATCH 15/22] integrated interface into bin semaphore --- osal/FreeRTOS/BinarySemaphore.cpp | 11 +++++++++++ osal/FreeRTOS/BinarySemaphore.h | 11 +++++++++-- tasks/SemaphoreIF.h | 14 +++++++------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index acfc53bdd..c0300b817 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -132,6 +132,17 @@ void BinarySemaphore::resetSemaphore() { } } +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + return takeBinarySemaphore(timeoutMs); +} + +ReturnValue_t BinarySemaphore::release() { + return giveBinarySemaphore(); +} + +uint8_t BinarySemaphore::getSemaphoreCounter() { + return uxSemaphoreGetCount(handle); +} // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 865da8a61..8271d9d09 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -2,7 +2,7 @@ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #include - +#include extern "C" { #include #include @@ -21,7 +21,8 @@ extern "C" { * @author R. Mueller * @ingroup osal */ -class BinarySemaphore: public HasReturnvaluesIF { +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -67,6 +68,12 @@ public: */ virtual ~BinarySemaphore(); + ReturnValue_t acquire(uint32_t timeoutMs = + BinarySemaphore::NO_BLOCK_TIMEOUT) override; + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() override; + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index cf56f6f90..616b992d0 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -9,10 +9,11 @@ * task synchronization. */ class SemaphoreIF { +public: + virtual~ SemaphoreIF() {}; //!< Needs to be defined in implementation. static const uint32_t NO_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; - //! Semaphore timeout static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); //! The current semaphore can not be given, because it is not owned @@ -26,24 +27,23 @@ class SemaphoreIF { * for a maximum of timeoutMs while trying to acquire the semaphore. * This can be used to achieve task synchrnization. * @param timeoutMs - * @return + * @return - c RETURN_OK for successfull acquisition */ - ReturnValue_t acquire(uint32_t timeoutMs) = 0; + virtual ReturnValue_t acquire(uint32_t timeoutMs) = 0; /** * Corrensponding call to release a semaphore. - * @return + * @return -@c RETURN_OK for successfull release */ - ReturnValue_t release() = 0; + virtual ReturnValue_t release() = 0; /** * If the semaphore is a counting semaphore then the semaphores current * count value is returned. If the semaphore is a binary semaphore then 1 * is returned if the semaphore is available, and 0 is returned if the * semaphore is not available. - * @return */ - uint8_t getSemaphoreCounter() = 0; + virtual uint8_t getSemaphoreCounter() = 0; }; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ -- 2.34.1 From b1d9d55f50a0e242ec57604934659c7fff50eb01 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:05 +0200 Subject: [PATCH 16/22] improved documentation --- tasks/SemaphoreIF.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 616b992d0..7dde27f43 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -6,7 +6,16 @@ /** * @brief Generic interface for semaphores, which can be used to achieve - * task synchronization. + * task synchronization. This is a generic interface which can be + * used for both binary semaphores and counting semaphores. + * @details + * A semaphore is a synchronization primitive. + * See: https://en.wikipedia.org/wiki/Semaphore_(programming) + * A semaphore can be used to achieve task synchonization and track the + * availability of resources. + * + * If mutual exlcusion of a resource is desired, a mutex should be used, + * which is a special form of a semaphore and has an own interface. */ class SemaphoreIF { public: -- 2.34.1 From 067cd9573100952c1398b956a8b7d2cbeab93a3a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:45 +0200 Subject: [PATCH 17/22] removed file header --- osal/FreeRTOS/BinarySemaphore.cpp | 5 ----- osal/FreeRTOS/BinarySemaphore.h | 1 - 2 files changed, 6 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index c0300b817..e48507020 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,8 +1,3 @@ -/** - * @file BinarySemaphore.cpp - * - * @date 25.02.2020 - */ #include #include diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 8271d9d09..854cbba42 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -71,7 +71,6 @@ public: ReturnValue_t acquire(uint32_t timeoutMs = BinarySemaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; /** -- 2.34.1 From 7227c3a8667a1ead8c4160b8372d350e79617de4 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:35:13 +0200 Subject: [PATCH 18/22] implemented semaph factory --- osal/FreeRTOS/BinarySemaphore.cpp | 45 +++++++++++++------------ osal/FreeRTOS/BinarySemaphore.h | 52 +++++++++++------------------ osal/FreeRTOS/CountingSemaphore.cpp | 26 +++++++++++++++ osal/FreeRTOS/CountingSemaphore.h | 21 ++++++++++++ osal/FreeRTOS/Mutex.h | 8 ++--- osal/FreeRTOS/MutexFactory.cpp | 9 ++--- osal/FreeRTOS/SemaphoreFactory.cpp | 33 ++++++++++++++++++ tasks/SemaphoreFactory.h | 45 +++++++++++++++++++++++++ 8 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 osal/FreeRTOS/CountingSemaphore.cpp create mode 100644 osal/FreeRTOS/CountingSemaphore.h create mode 100644 osal/FreeRTOS/SemaphoreFactory.cpp create mode 100644 tasks/SemaphoreFactory.h diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index e48507020..11e481531 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,21 +3,21 @@ #include -BinarySemaphore::BinarySemaphore() { +Semaphore::Semaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } xSemaphoreGive(handle); } -BinarySemaphore::~BinarySemaphore() { +Semaphore::~Semaphore() { 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) { +Semaphore::Semaphore(const Semaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -25,7 +25,7 @@ BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { xSemaphoreGive(handle); } -BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { +Semaphore& Semaphore::operator =(const Semaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -36,7 +36,7 @@ BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { return *this; } -BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { +Semaphore::Semaphore(Semaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -44,8 +44,8 @@ BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { xSemaphoreGive(handle); } -BinarySemaphore& BinarySemaphore::operator =( - BinarySemaphore&& s) { +Semaphore& Semaphore::operator =( + Semaphore&& s) { if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -56,15 +56,15 @@ BinarySemaphore& BinarySemaphore::operator =( return *this; } -ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { +ReturnValue_t Semaphore::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; + TickType_t timeout = Semaphore::NO_BLOCK_TICKS; + if(timeoutMs == Semaphore::BLOCK_TIMEOUT) { + timeout = Semaphore::BLOCK_TIMEOUT_TICKS; } - else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > Semaphore::NO_BLOCK_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -77,7 +77,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { } } -ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( +ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -91,7 +91,7 @@ ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( } } -ReturnValue_t BinarySemaphore::giveBinarySemaphore() { +ReturnValue_t Semaphore::giveBinarySemaphore() { if (handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -103,11 +103,11 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore() { } } -SemaphoreHandle_t BinarySemaphore::getSemaphore() { +SemaphoreHandle_t Semaphore::getSemaphore() { return handle; } -ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { +ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -119,7 +119,7 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) } } -void BinarySemaphore::resetSemaphore() { +void Semaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); handle = xSemaphoreCreateBinary(); @@ -127,20 +127,20 @@ void BinarySemaphore::resetSemaphore() { } } -ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { +ReturnValue_t Semaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); } -ReturnValue_t BinarySemaphore::release() { +ReturnValue_t Semaphore::release() { return giveBinarySemaphore(); } -uint8_t BinarySemaphore::getSemaphoreCounter() { +uint8_t Semaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, +ReturnValue_t Semaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -157,3 +157,4 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema return SEMAPHORE_NOT_OWNED; } } + diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 854cbba42..6383432f7 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -14,14 +14,16 @@ extern "C" { // and switch between the classes with #ifdefs. // Task Notifications require FreeRTOS V8.2 something.. /** - * @brief OS Tool to achieve synchronization of between tasks or between task and ISR + * @brief OS Tool to achieve synchronization of between tasks or between + * task and ISR. The default semaphore implementation creates a + * binary semaphore, which can only be taken once. * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * * @author R. Mueller * @ingroup osal */ -class BinarySemaphore: public SemaphoreIF, +class Semaphore: public SemaphoreIF, public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -41,35 +43,21 @@ public: 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(); + //! @brief Default ctor + Semaphore(); + //! @brief Copy ctor + Semaphore(const Semaphore&); + //! @brief Copy assignment + Semaphore& operator=(const Semaphore&); + //! @brief Move ctor + Semaphore (Semaphore &&); + //! @brief Move assignment + Semaphore & operator=(Semaphore &&); + //! @brief Destructor + virtual ~Semaphore(); ReturnValue_t acquire(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT) override; + Semaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; @@ -83,7 +71,7 @@ public: * -@c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT); + Semaphore::NO_BLOCK_TIMEOUT); /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -92,7 +80,7 @@ public: * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - BinarySemaphore::NO_BLOCK_TICKS); + Semaphore::NO_BLOCK_TICKS); /** * Give back the binary semaphore @@ -130,7 +118,7 @@ public: */ static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); -private: +protected: SemaphoreHandle_t handle; }; diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp new file mode 100644 index 000000000..adf3f23c9 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -0,0 +1,26 @@ +#include +#include + +CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): + count(count), initCount(initCount) { + handle = xSemaphoreCreateCounting(count, initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.count, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + handle = xSemaphoreCreateCounting(other.count, other.initCount); + if(handle == nullptr) { + sif::error << "CountingSemaphore: Creation failure" << std::endl; + } + return * this; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h new file mode 100644 index 000000000..8c059af52 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -0,0 +1,21 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ +#include + +class CountingSemaphore: public Semaphore { +public: + CountingSemaphore(uint8_t count, uint8_t initCount); + //! @brief Copy ctor, disabled + CountingSemaphore(const CountingSemaphore&) = delete; + //! @brief Copy assignment, disabled + CountingSemaphore& operator=(const CountingSemaphore&) = delete; + //! @brief Move ctor + CountingSemaphore (CountingSemaphore &&); + //! @brief Move assignment + CountingSemaphore & operator=(CountingSemaphore &&); +private: + uint8_t count = 0; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index 91f295853..ccbcad26c 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -3,10 +3,10 @@ #include - -#include -#include "semphr.h" - +extern "C" { +#include +#include +} class Mutex : public MutexIF { diff --git a/osal/FreeRTOS/MutexFactory.cpp b/osal/FreeRTOS/MutexFactory.cpp index cadb54fbd..08cd68c8b 100644 --- a/osal/FreeRTOS/MutexFactory.cpp +++ b/osal/FreeRTOS/MutexFactory.cpp @@ -1,10 +1,11 @@ #include -#include "../FreeRTOS/Mutex.h" +#include -//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? -> one is on heap the other on bss/data +//TODO: Different variant than the lazy loading in QueueFactory. +//What's better and why? -> one is on heap the other on bss/data //MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); -MutexFactory* MutexFactory::factoryInstance = NULL; +MutexFactory* MutexFactory::factoryInstance = nullptr; MutexFactory::MutexFactory() { } @@ -13,7 +14,7 @@ MutexFactory::~MutexFactory() { } MutexFactory* MutexFactory::instance() { - if (factoryInstance == NULL){ + if (factoryInstance == nullptr){ factoryInstance = new MutexFactory(); } return MutexFactory::factoryInstance; diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp new file mode 100644 index 000000000..dd319025d --- /dev/null +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; + +SemaphoreFactory::SemaphoreFactory() { +} + +SemaphoreFactory::~SemaphoreFactory() { + delete factoryInstance; +} + +SemaphoreFactory* SemaphoreFactory::instance() { + if (factoryInstance == nullptr){ + factoryInstance = new SemaphoreFactory(); + } + return SemaphoreFactory::factoryInstance; +} + +SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { + return new Semaphore(); +} + +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, + uint8_t initCount) { + return new CountingSemaphore(count, initCount); +} + +void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { + delete semaphore; +} diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h new file mode 100644 index 000000000..fa95399a1 --- /dev/null +++ b/tasks/SemaphoreFactory.h @@ -0,0 +1,45 @@ +#ifndef FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#define FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ +#include + +/** + * Creates Semaphore. + * This class is a "singleton" interface, i.e. it provides an + * interface, but also is the base class for a singleton. + */ +class SemaphoreFactory { +public: + virtual ~SemaphoreFactory(); + /** + * Returns the single instance of SemaphoreFactory. + * The implementation of #instance is found in its subclasses. + * Thus, we choose link-time variability of the instance. + */ + static SemaphoreFactory* instance(); + + /** + * Create a binary semaphore. + * Creator function for a binary semaphore which may only be acquired once + * @return Pointer to newly created semaphore class instance. + */ + SemaphoreIF* createBinarySemaphore(); + /** + * Create a counting semaphore. + * Creator functons for a counting semaphore which may be acquired multiple + * times. + * @param count Semaphore can be taken count times. + * @param initCount Initial count value. + * @return + */ + SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount); + void deleteMutex(SemaphoreIF* mutex); + +private: + /** + * External instantiation is not allowed. + */ + SemaphoreFactory(); + static SemaphoreFactory* factoryInstance; +}; + +#endif /* FRAMEWORK_TASKS_SEMAPHOREFACTORY_H_ */ -- 2.34.1 From 066930b110730c8c781f0b680e1f7b99f1dbe920 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:39:48 +0200 Subject: [PATCH 19/22] improvements --- osal/FreeRTOS/BinarySemaphore.cpp | 42 +++++++++++++++--------------- osal/FreeRTOS/BinarySemaphore.h | 20 +++++++------- osal/FreeRTOS/CountingSemaphore.h | 10 ++++++- osal/FreeRTOS/SemaphoreFactory.cpp | 2 +- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 11e481531..f08e3b814 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -3,7 +3,7 @@ #include -Semaphore::Semaphore() { +BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Semaphore: Binary semaph creation failure" << std::endl; @@ -11,13 +11,13 @@ Semaphore::Semaphore() { xSemaphoreGive(handle); } -Semaphore::~Semaphore() { +BinarySemaphore::~BinarySemaphore() { vSemaphoreDelete(handle); } // This copy ctor is important as it prevents the assignment to a ressource // (other.handle) variable which is later deleted! -Semaphore::Semaphore(const Semaphore& other) { +BinarySemaphore::BinarySemaphore(const BinarySemaphore& other) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -25,7 +25,7 @@ Semaphore::Semaphore(const Semaphore& other) { xSemaphoreGive(handle); } -Semaphore& Semaphore::operator =(const Semaphore& s) { +BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { if(this != &s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -36,7 +36,7 @@ Semaphore& Semaphore::operator =(const Semaphore& s) { return *this; } -Semaphore::Semaphore(Semaphore&& s) { +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { sif::error << "Binary semaphore creation failure" << std::endl; @@ -44,8 +44,8 @@ Semaphore::Semaphore(Semaphore&& s) { xSemaphoreGive(handle); } -Semaphore& Semaphore::operator =( - Semaphore&& s) { +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { if(&s != this) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -56,15 +56,15 @@ Semaphore& Semaphore::operator =( return *this; } -ReturnValue_t Semaphore::takeBinarySemaphore(uint32_t timeoutMs) { +ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; } - TickType_t timeout = Semaphore::NO_BLOCK_TICKS; - if(timeoutMs == Semaphore::BLOCK_TIMEOUT) { - timeout = Semaphore::BLOCK_TIMEOUT_TICKS; + TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; + if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { + timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; } - else if(timeoutMs > Semaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -77,7 +77,7 @@ ReturnValue_t Semaphore::takeBinarySemaphore(uint32_t timeoutMs) { } } -ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( +ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( TickType_t timeoutTicks) { if(handle == nullptr) { return SEMAPHORE_NULLPOINTER; @@ -91,7 +91,7 @@ ReturnValue_t Semaphore::takeBinarySemaphoreTickTimeout( } } -ReturnValue_t Semaphore::giveBinarySemaphore() { +ReturnValue_t BinarySemaphore::giveBinarySemaphore() { if (handle == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -103,11 +103,11 @@ ReturnValue_t Semaphore::giveBinarySemaphore() { } } -SemaphoreHandle_t Semaphore::getSemaphore() { +SemaphoreHandle_t BinarySemaphore::getSemaphore() { return handle; } -ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { +ReturnValue_t BinarySemaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; } @@ -119,7 +119,7 @@ ReturnValue_t Semaphore::giveBinarySemaphore(SemaphoreHandle_t semaphore) { } } -void Semaphore::resetSemaphore() { +void BinarySemaphore::resetSemaphore() { if(handle != nullptr) { vSemaphoreDelete(handle); handle = xSemaphoreCreateBinary(); @@ -127,20 +127,20 @@ void Semaphore::resetSemaphore() { } } -ReturnValue_t Semaphore::acquire(uint32_t timeoutMs) { +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); } -ReturnValue_t Semaphore::release() { +ReturnValue_t BinarySemaphore::release() { return giveBinarySemaphore(); } -uint8_t Semaphore::getSemaphoreCounter() { +uint8_t BinarySemaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); } // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t Semaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, +ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { return SEMAPHORE_NULLPOINTER; diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 6383432f7..bd4ddb953 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -23,7 +23,7 @@ extern "C" { * @author R. Mueller * @ingroup osal */ -class Semaphore: public SemaphoreIF, +class BinarySemaphore: public SemaphoreIF, public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -44,20 +44,20 @@ public: static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); //! @brief Default ctor - Semaphore(); + BinarySemaphore(); //! @brief Copy ctor - Semaphore(const Semaphore&); + BinarySemaphore(const BinarySemaphore&); //! @brief Copy assignment - Semaphore& operator=(const Semaphore&); + BinarySemaphore& operator=(const BinarySemaphore&); //! @brief Move ctor - Semaphore (Semaphore &&); + BinarySemaphore (BinarySemaphore &&); //! @brief Move assignment - Semaphore & operator=(Semaphore &&); + BinarySemaphore & operator=(BinarySemaphore &&); //! @brief Destructor - virtual ~Semaphore(); + virtual ~BinarySemaphore(); ReturnValue_t acquire(uint32_t timeoutMs = - Semaphore::NO_BLOCK_TIMEOUT) override; + BinarySemaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; @@ -71,7 +71,7 @@ public: * -@c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - Semaphore::NO_BLOCK_TIMEOUT); + BinarySemaphore::NO_BLOCK_TIMEOUT); /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. @@ -80,7 +80,7 @@ public: * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - Semaphore::NO_BLOCK_TICKS); + BinarySemaphore::NO_BLOCK_TICKS); /** * Give back the binary semaphore diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index 8c059af52..a33a0fa5a 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -2,7 +2,15 @@ #define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ #include -class CountingSemaphore: public Semaphore { +/** + * @brief Counting semaphores, which can be acquire more than once. + * @details + * See: https://www.freertos.org/CreateCounting.html + * API of counting semaphores is almost identical to binary semaphores, + * so we just inherit from binary semaphore and provide the respective + * constructors. + */ +class CountingSemaphore: public BinarySemaphore { public: CountingSemaphore(uint8_t count, uint8_t initCount); //! @brief Copy ctor, disabled diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index dd319025d..9a3558913 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -20,7 +20,7 @@ SemaphoreFactory* SemaphoreFactory::instance() { } SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { - return new Semaphore(); + return new BinarySemaphore(); } SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, -- 2.34.1 From e56bef7e00a3e6de7d994318642c371a2583e921 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 20 May 2020 12:53:02 +0200 Subject: [PATCH 20/22] deleted copyctor and copy assignmentt --- osal/FreeRTOS/BinarySemaphore.cpp | 32 +++++-------------------------- osal/FreeRTOS/BinarySemaphore.h | 25 ++++++++++-------------- 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index f08e3b814..026704d63 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -5,8 +5,8 @@ BinarySemaphore::BinarySemaphore() { handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Semaphore: Binary semaph creation failure" << std::endl; + if(handle == nullptr) { + sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } xSemaphoreGive(handle); } @@ -15,27 +15,6 @@ 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) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); -} - -BinarySemaphore& BinarySemaphore::operator =(const BinarySemaphore& s) { - if(this != &s) { - handle = xSemaphoreCreateBinary(); - if(handle == nullptr) { - sif::error << "Binary semaphore creation failure" << std::endl; - } - xSemaphoreGive(handle); - } - return *this; -} - BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { handle = xSemaphoreCreateBinary(); if(handle == nullptr) { @@ -126,7 +105,7 @@ void BinarySemaphore::resetSemaphore() { xSemaphoreGive(handle); } } - + ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { return takeBinarySemaphore(timeoutMs); } @@ -137,7 +116,7 @@ ReturnValue_t BinarySemaphore::release() { uint8_t BinarySemaphore::getSemaphoreCounter() { return uxSemaphoreGetCount(handle); -} +} // Be careful with the stack size here. This is called from an ISR! ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, @@ -156,5 +135,4 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema } else { return SEMAPHORE_NOT_OWNED; } -} - +} diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index bd4ddb953..5f69dc90b 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -1,7 +1,7 @@ #ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ #define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ -#include +#include #include extern "C" { #include @@ -24,7 +24,7 @@ extern "C" { * @ingroup osal */ class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { + public HasReturnvaluesIF { public: static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; @@ -36,19 +36,13 @@ public: //! 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); - + //! @brief Default ctor BinarySemaphore(); - //! @brief Copy ctor - BinarySemaphore(const BinarySemaphore&); - //! @brief Copy assignment - BinarySemaphore& operator=(const BinarySemaphore&); + //! @brief Copy ctor, deleted explicitely. + BinarySemaphore(const BinarySemaphore&) = delete; + //! @brief Copy assignment, deleted explicitely. + BinarySemaphore& operator=(const BinarySemaphore&) = delete; //! @brief Move ctor BinarySemaphore (BinarySemaphore &&); //! @brief Move assignment @@ -60,7 +54,7 @@ public: BinarySemaphore::NO_BLOCK_TIMEOUT) override; ReturnValue_t release() override; uint8_t getSemaphoreCounter() override; - + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked @@ -118,7 +112,8 @@ public: */ static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); -protected: + +protected: SemaphoreHandle_t handle; }; -- 2.34.1 From c2d758eb9654e3ceecd9109ee11ac93015eda5e7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 27 May 2020 16:53:41 +0200 Subject: [PATCH 21/22] added new MAX_TIMEOUT value --- osal/FreeRTOS/CountingSemaphore.cpp | 2 ++ osal/FreeRTOS/SemaphoreFactory.cpp | 2 ++ tasks/SemaphoreIF.h | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index adf3f23c9..2b81848a2 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,6 +1,8 @@ #include #include +// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in +// free FreeRTOSConfig.h file. CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): count(count), initCount(initCount) { handle = xSemaphoreCreateCounting(count, initCount); diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 9a3558913..7bd71dd7a 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -4,6 +4,8 @@ #include SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; +const uint32_t SemaphoreIF::NO_TIMEOUT = 0; +const uint32_t SemaphoreIF::MAX_TIMEOUT = portMAX_DELAY; SemaphoreFactory::SemaphoreFactory() { } diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 7dde27f43..b2b113f17 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -20,8 +20,10 @@ class SemaphoreIF { public: virtual~ SemaphoreIF() {}; - //!< Needs to be defined in implementation. + //! Needs to be defined in implementation. No blocking time static const uint32_t NO_TIMEOUT; + //! Needs to be defined in implementation. Blocks indefinitely. + static const uint32_t MAX_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; //! Semaphore timeout static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1); -- 2.34.1 From a64813e9fc8f492977cae3bf02887de29c09e989 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 29 May 2020 13:23:52 +0200 Subject: [PATCH 22/22] updates: improvements across the board --- osal/FreeRTOS/BinSemaphUsingTask.cpp | 91 ++++++++++++++++++ osal/FreeRTOS/BinSemaphUsingTask.h | 75 +++++++++++++++ osal/FreeRTOS/BinarySemaphore.cpp | 105 +++++++-------------- osal/FreeRTOS/BinarySemaphore.h | 83 +++++++--------- osal/FreeRTOS/CountingSemaphUsingTask.cpp | 110 ++++++++++++++++++++++ osal/FreeRTOS/CountingSemaphUsingTask.h | 100 ++++++++++++++++++++ osal/FreeRTOS/CountingSemaphore.cpp | 27 ++++-- osal/FreeRTOS/CountingSemaphore.h | 9 +- osal/FreeRTOS/MessageQueue.cpp | 4 +- osal/FreeRTOS/MessageQueue.h | 11 +-- osal/FreeRTOS/TaskManagement.cpp | 8 +- osal/FreeRTOS/TaskManagement.h | 19 ++-- tasks/SemaphoreFactory.h | 10 +- tasks/SemaphoreIF.h | 7 +- 14 files changed, 505 insertions(+), 154 deletions(-) create mode 100644 osal/FreeRTOS/BinSemaphUsingTask.cpp create mode 100644 osal/FreeRTOS/BinSemaphUsingTask.h create mode 100644 osal/FreeRTOS/CountingSemaphUsingTask.cpp create mode 100644 osal/FreeRTOS/CountingSemaphUsingTask.h diff --git a/osal/FreeRTOS/BinSemaphUsingTask.cpp b/osal/FreeRTOS/BinSemaphUsingTask.cpp new file mode 100644 index 000000000..8f5fd4d8a --- /dev/null +++ b/osal/FreeRTOS/BinSemaphUsingTask.cpp @@ -0,0 +1,91 @@ +#include +#include +#include + +BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() { + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "Could not retrieve task handle. Please ensure the" + "constructor was called inside a task." << std::endl; + } + xTaskNotifyGive(handle); +} + +BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() { + // Clear notification value on destruction. + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquire(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; + } + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + return acquireWithTickTimeout(timeout); +} + +ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout( + TickType_t timeoutTicks) { + BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t BinarySemaphoreUsingTask::release() { + return release(this->handle); +} + +ReturnValue_t BinarySemaphoreUsingTask::release( + TaskHandle_t taskHandle) { + if(getSemaphoreCounter(taskHandle) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + BaseType_t returncode = xTaskNotifyGive(taskHandle); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() { + return handle; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const { + return getSemaphoreCounter(this->handle); +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter( + TaskHandle_t taskHandle) { + uint32_t notificationValue; + xTaskNotifyAndQuery(taskHandle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +// Be careful with the stack size here. This is called from an ISR! +ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) { + if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue = 0; + xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} diff --git a/osal/FreeRTOS/BinSemaphUsingTask.h b/osal/FreeRTOS/BinSemaphUsingTask.h new file mode 100644 index 000000000..48c1cd12d --- /dev/null +++ b/osal/FreeRTOS/BinSemaphUsingTask.h @@ -0,0 +1,75 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ + +#include +#include + +#include +#include + +/** + * @brief Binary Semaphore implementation using the task notification value. + * The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class BinarySemaphoreUsingTask: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + BinarySemaphoreUsingTask(); + //! @brief Default dtor + virtual~ BinarySemaphoreUsingTask(); + + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; + ReturnValue_t release() override; + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle); + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle, + BaseType_t* higherPriorityTaskWoken); + + /** + * Same as acquire() with timeout in FreeRTOS ticks. + * @param timeoutTicks + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = + SemaphoreIF::NO_TIMEOUT); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Wrapper function to give back semaphore from handle + * @param semaphore + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + + /** + * 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. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t * higherPriorityTaskWoken); + +protected: + TaskHandle_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 026704d63..b6687bb75 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -1,6 +1,5 @@ #include #include - #include BinarySemaphore::BinarySemaphore() { @@ -8,6 +7,7 @@ BinarySemaphore::BinarySemaphore() { if(handle == nullptr) { sif::error << "Semaphore: Binary semaph creation failure" << std::endl; } + // Initiated semaphore must be given before it can be taken. xSemaphoreGive(handle); } @@ -35,104 +35,69 @@ BinarySemaphore& BinarySemaphore::operator =( return *this; } -ReturnValue_t BinarySemaphore::takeBinarySemaphore(uint32_t timeoutMs) { - if(handle == nullptr) { - return SEMAPHORE_NULLPOINTER; +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; } - TickType_t timeout = BinarySemaphore::NO_BLOCK_TICKS; - if(timeoutMs == BinarySemaphore::BLOCK_TIMEOUT) { - timeout = BinarySemaphore::BLOCK_TIMEOUT_TICKS; - } - else if(timeoutMs > BinarySemaphore::NO_BLOCK_TIMEOUT){ + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } - - BaseType_t returncode = xSemaphoreTake(handle, timeout); - if (returncode == pdPASS) { - return HasReturnvaluesIF::RETURN_OK; - } - else { - return SEMAPHORE_TIMEOUT; - } + return acquireWithTickTimeout(timeout); } -ReturnValue_t BinarySemaphore::takeBinarySemaphoreTickTimeout( - TickType_t timeoutTicks) { +ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TickType_t timeoutTicks) { if(handle == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_INVALID; } BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_TIMEOUT; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; } } -ReturnValue_t BinarySemaphore::giveBinarySemaphore() { - if (handle == nullptr) { - return SEMAPHORE_NULLPOINTER; +ReturnValue_t BinarySemaphore::release() { + return release(handle); +} + +ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) { + if (semaphore == nullptr) { + return SemaphoreIF::SEMAPHORE_INVALID; } - BaseType_t returncode = xSemaphoreGive(handle); + BaseType_t returncode = xSemaphoreGive(semaphore); if (returncode == pdPASS) { return HasReturnvaluesIF::RETURN_OK; - } else { - return SEMAPHORE_NOT_OWNED; } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + return uxSemaphoreGetCount(handle); } 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); - handle = xSemaphoreCreateBinary(); - xSemaphoreGive(handle); - } -} -ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { - return takeBinarySemaphore(timeoutMs); -} - -ReturnValue_t BinarySemaphore::release() { - return giveBinarySemaphore(); -} - -uint8_t BinarySemaphore::getSemaphoreCounter() { - return uxSemaphoreGetCount(handle); -} // Be careful with the stack size here. This is called from an ISR! -ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, - BaseType_t * higherPriorityTaskWoken) { +ReturnValue_t BinarySemaphore::releaseFromISR( + SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) { if (semaphore == nullptr) { - return SEMAPHORE_NULLPOINTER; + return SemaphoreIF::SEMAPHORE_INVALID; } - BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); + 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; + } + else { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; } } diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 5f69dc90b..0938dee6f 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -3,16 +3,10 @@ #include #include -extern "C" { + #include #include -} -// TODO: Counting semaphores and implement the new (better) -// task notifications. However, those use task notifications require -// the task handle. Maybe it would be better to make a separate class -// and switch between the classes with #ifdefs. -// Task Notifications require FreeRTOS V8.2 something.. /** * @brief OS Tool to achieve synchronization of between tasks or between * task and ISR. The default semaphore implementation creates a @@ -20,23 +14,20 @@ extern "C" { * @details * Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html * + * Please note that if the semaphore implementation is only related to + * the synchronization of one task, the new task notifications can be used, + * also see the BinSemaphUsingTask and CountingSemaphUsingTask classes. + * These use the task notification value instead of a queue and are + * faster and more efficient. + * * @author R. Mueller * @ingroup osal */ class BinarySemaphore: public SemaphoreIF, - public HasReturnvaluesIF { + 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; - //! @brief Default ctor BinarySemaphore(); //! @brief Copy ctor, deleted explicitely. @@ -50,11 +41,8 @@ public: //! @brief Destructor virtual ~BinarySemaphore(); - ReturnValue_t acquire(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT) override; - ReturnValue_t release() override; - uint8_t getSemaphoreCounter() override; - + uint8_t getSemaphoreCounter() const override; + /** * Take the binary semaphore. * If the semaphore has already been taken, the task will be blocked @@ -62,26 +50,27 @@ public: * for example by an ISR or another task. * @param timeoutMs * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ - ReturnValue_t takeBinarySemaphore(uint32_t timeoutMs = - BinarySemaphore::NO_BLOCK_TIMEOUT); + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. * @param timeoutTicks - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout */ - ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = - BinarySemaphore::NO_BLOCK_TICKS); + ReturnValue_t acquireWithTickTimeout(TickType_t timeoutTicks = + BinarySemaphore::NO_TIMEOUT); /** - * Give back the binary semaphore - * @return - @c RETURN_OK on success - * - @c RETURN_FAILED on failure + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ - ReturnValue_t giveBinarySemaphore(); + ReturnValue_t release() override; /** * Get Handle to the semaphore. @@ -89,31 +78,29 @@ public: */ 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 + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ - static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); + static ReturnValue_t release(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 + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch from an ISR should + * then be requested (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. */ - static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, + static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); - -protected: + +protected: SemaphoreHandle_t handle; }; diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.cpp b/osal/FreeRTOS/CountingSemaphUsingTask.cpp new file mode 100644 index 000000000..d0f63f3f9 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphUsingTask.cpp @@ -0,0 +1,110 @@ +#include +#include +#include + +CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount, + uint8_t initCount): maxCount(maxCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = TaskManagement::getCurrentTaskHandle(); + if(handle == nullptr) { + sif::error << "CountingSemaphoreUsingTask: Could not retrieve task " + "handle. Please ensure the constructor was called inside a " + "task." << std::endl; + } + + uint32_t oldNotificationValue; + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, + &oldNotificationValue); + if(oldNotificationValue != 0) { + sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but " + "current notification value is not 0. Please ensure the " + "notification value is not used for other purposes!" << std::endl; + } + for(int i = 0; i < initCount; i++) { + xTaskNotifyGive(handle); + } +} + +CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() { + // Clear notification value on destruction. + // If this is not desired, don't call the destructor + // (or implement a boolean which disables the reset) + xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr); +} + +ReturnValue_t CountingSemaphoreUsingTask::acquire(uint32_t timeoutMs) { + TickType_t timeout = SemaphoreIF::NO_TIMEOUT; + if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + timeout = SemaphoreIF::MAX_TIMEOUT; + } + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ + timeout = pdMS_TO_TICKS(timeoutMs); + } + return acquireWithTickTimeout(timeout); + +} + +ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout( + TickType_t timeoutTicks) { + // Decrement notfication value without resetting it. + BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks); + if (getSemaphoreCounter() == oldCount - 1) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return SemaphoreIF::SEMAPHORE_TIMEOUT; + } +} + +ReturnValue_t CountingSemaphoreUsingTask::release() { + if(getSemaphoreCounter() == maxCount) { + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return release(handle); +} + +ReturnValue_t CountingSemaphoreUsingTask::release( + TaskHandle_t taskToNotify) { + BaseType_t returncode = xTaskNotifyGive(taskToNotify); + if (returncode == pdPASS) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + // This should never happen. + return HasReturnvaluesIF::RETURN_FAILED; + } +} + + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const { + uint32_t notificationValue = 0; + xTaskNotifyAndQuery(handle, 0, eNoAction, ¬ificationValue); + return notificationValue; +} + +TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() { + return handle; +} + +ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR( + TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) { + vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken); + return HasReturnvaluesIF::RETURN_OK; +} + +uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR( + TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) { + uint32_t notificationValue; + xTaskNotifyAndQueryFromISR(task, 0, eNoAction, ¬ificationValue, + higherPriorityTaskWoken); + return notificationValue; +} + +uint8_t CountingSemaphoreUsingTask::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphUsingTask.h b/osal/FreeRTOS/CountingSemaphUsingTask.h new file mode 100644 index 000000000..797e864b5 --- /dev/null +++ b/osal/FreeRTOS/CountingSemaphUsingTask.h @@ -0,0 +1,100 @@ +#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ +#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ + +#include +#include + +extern "C" { +#include +#include +} + +/** + * @brief Couting Semaphore implementation which uses the notification value + * of the task. The notification value should therefore not be used + * for other purposes. + * @details + * Additional information: https://www.freertos.org/RTOS-task-notifications.html + * and general semaphore documentation. + */ +class CountingSemaphoreUsingTask: public SemaphoreIF { +public: + CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount); + virtual ~CountingSemaphoreUsingTask(); + + /** + * Acquire the counting semaphore. + * If no semaphores are available, the task will be blocked + * for a maximum of #timeoutMs or until one is given back, + * for example by an ISR or another task. + * @param timeoutMs + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(uint32_t timeoutMs = SemaphoreIF::NO_TIMEOUT) override; + + /** + * Release a semaphore, increasing the number of available counting + * semaphores up to the #maxCount value. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + ReturnValue_t release() override; + + uint8_t getSemaphoreCounter() const override; + /** + * Get the semaphore counter from an ISR. + * @param task + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return + */ + static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task, + BaseType_t* higherPriorityTaskWoken); + + /** + * Acquire with a timeout value in ticks + * @param timeoutTicks + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquireWithTickTimeout( + TickType_t timeoutTicks = SemaphoreIF::NO_TIMEOUT); + + /** + * Get handle to the task related to the semaphore. + * @return + */ + TaskHandle_t getTaskHandle(); + + /** + * Release semaphore of task by supplying task handle + * @param taskToNotify + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t release(TaskHandle_t taskToNotify); + /** + * Release seamphore of a task from an ISR. + * @param taskToNotify + * @param higherPriorityTaskWoken This will be set to pdPASS if a task with + * a higher priority was unblocked. A context switch should be requested + * from an ISR if this is the case (see TaskManagement functions) + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are + * already available. + */ + static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify, + BaseType_t* higherPriorityTaskWoken); + + uint8_t getMaxCount() const; + +private: + TaskHandle_t handle; + const uint8_t maxCount; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */ diff --git a/osal/FreeRTOS/CountingSemaphore.cpp b/osal/FreeRTOS/CountingSemaphore.cpp index 2b81848a2..957f6a319 100644 --- a/osal/FreeRTOS/CountingSemaphore.cpp +++ b/osal/FreeRTOS/CountingSemaphore.cpp @@ -1,18 +1,28 @@ #include #include +#include + +#include // Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in // free FreeRTOSConfig.h file. -CountingSemaphore::CountingSemaphore(uint8_t count, uint8_t initCount): - count(count), initCount(initCount) { - handle = xSemaphoreCreateCounting(count, initCount); +CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount): + maxCount(maxCount), initCount(initCount) { + if(initCount > maxCount) { + sif::error << "CountingSemaphoreUsingTask: Max count bigger than " + "intial cout. Setting initial count to max count." << std::endl; + initCount = maxCount; + } + + handle = xSemaphoreCreateCounting(maxCount, initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } } -CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.count, other.initCount); +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } @@ -20,9 +30,14 @@ CountingSemaphore::CountingSemaphore(CountingSemaphore&& other) { CountingSemaphore& CountingSemaphore::operator =( CountingSemaphore&& other) { - handle = xSemaphoreCreateCounting(other.count, other.initCount); + handle = xSemaphoreCreateCounting(other.maxCount, other.initCount); if(handle == nullptr) { sif::error << "CountingSemaphore: Creation failure" << std::endl; } return * this; } + + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} diff --git a/osal/FreeRTOS/CountingSemaphore.h b/osal/FreeRTOS/CountingSemaphore.h index a33a0fa5a..dca3ab0ed 100644 --- a/osal/FreeRTOS/CountingSemaphore.h +++ b/osal/FreeRTOS/CountingSemaphore.h @@ -12,7 +12,7 @@ */ class CountingSemaphore: public BinarySemaphore { public: - CountingSemaphore(uint8_t count, uint8_t initCount); + CountingSemaphore(const uint8_t maxCount, uint8_t initCount); //! @brief Copy ctor, disabled CountingSemaphore(const CountingSemaphore&) = delete; //! @brief Copy assignment, disabled @@ -21,8 +21,13 @@ public: CountingSemaphore (CountingSemaphore &&); //! @brief Move assignment CountingSemaphore & operator=(CountingSemaphore &&); + + /* Same API as binary semaphore otherwise. acquire() can be called + * until there are not semaphores left and release() can be called + * until maxCount is reached. */ + uint8_t getMaxCount() const; private: - uint8_t count = 0; + const uint8_t maxCount; uint8_t initCount = 0; }; diff --git a/osal/FreeRTOS/MessageQueue.cpp b/osal/FreeRTOS/MessageQueue.cpp index 9e4b581be..0a579296b 100644 --- a/osal/FreeRTOS/MessageQueue.cpp +++ b/osal/FreeRTOS/MessageQueue.cpp @@ -1,4 +1,4 @@ -#include "MessageQueue.h" +#include #include @@ -124,7 +124,7 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, bool ignoreFault, CallContext callContext) { message->setSender(sentFrom); BaseType_t result; - if(callContext == CallContext::task) { + if(callContext == CallContext::TASK) { result = xQueueSendToBack(reinterpret_cast(sendTo), static_cast(message->getBuffer()), 0); } diff --git a/osal/FreeRTOS/MessageQueue.h b/osal/FreeRTOS/MessageQueue.h index 07e95ddf5..81b4c186d 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -6,13 +6,12 @@ #include #include -extern "C" { #include #include -} - -//TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution +// TODO: this class assumes that MessageQueueId_t is the same size as void* +// (the FreeRTOS handle type), compiler will catch this but it might be nice +// to have something checking or even an always working solution // https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ /** @@ -193,7 +192,7 @@ protected: */ static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE, - bool ignoreFault=false, CallContext callContext = CallContext::task); + bool ignoreFault=false, CallContext callContext = CallContext::TASK); static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); @@ -203,7 +202,7 @@ private: MessageQueueId_t defaultDestination = 0; MessageQueueId_t lastPartner = 0; //!< Stores the current system context - CallContext callContext = CallContext::task; + CallContext callContext = CallContext::TASK; }; #endif /* MESSAGEQUEUE_H_ */ diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index cc1bdae19..7871ab2ec 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -3,10 +3,10 @@ void TaskManagement::requestContextSwitchFromTask() { vTaskDelay(0); } - + void TaskManagement::requestContextSwitch( - CallContext callContext = CallContext::task) { - if(callContext == CallContext::isr) { + CallContext callContext = CallContext::TASK) { + if(callContext == CallContext::ISR) { // This function depends on the partmacro.h definition for the specific device requestContextSwitchFromISR(); } else { @@ -20,4 +20,4 @@ TaskHandle_t TaskManagement::getCurrentTaskHandle() { configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() { return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle()); -} +} diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index 858431674..39c24377b 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -17,31 +17,30 @@ 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 + * 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. + * an ISR and task. */ - -enum CallContext { - task = 0x00,//!< task_context - isr = 0xFF //!< isr_context +enum class CallContext { + TASK = 0x00,//!< task_context + ISR = 0xFF //!< isr_context }; class TaskManagement { public: - /** + /** * @brief 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. + * 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); /** @@ -57,7 +56,7 @@ public: * E.g. on a 32 bit machine, a value of 200 means 800 bytes. * @return Smallest value of stack remaining since the task was started in * words. - */ + */ static configSTACK_DEPTH_TYPE getTaskStackHighWatermark(); }; diff --git a/tasks/SemaphoreFactory.h b/tasks/SemaphoreFactory.h index fa95399a1..7f8edaf12 100644 --- a/tasks/SemaphoreFactory.h +++ b/tasks/SemaphoreFactory.h @@ -20,19 +20,23 @@ public: /** * Create a binary semaphore. * Creator function for a binary semaphore which may only be acquired once + * @param argument Can be used to pass implementation specific information. * @return Pointer to newly created semaphore class instance. */ - SemaphoreIF* createBinarySemaphore(); + SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0); /** * Create a counting semaphore. * Creator functons for a counting semaphore which may be acquired multiple * times. * @param count Semaphore can be taken count times. * @param initCount Initial count value. + * @param argument Can be used to pass implementation specific information. * @return */ - SemaphoreIF* createCountingSemaphore(uint8_t count, uint8_t initCount); - void deleteMutex(SemaphoreIF* mutex); + SemaphoreIF* createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments = 0); + + void deleteSemaphore(SemaphoreIF* semaphore); private: /** diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index b2b113f17..a7c5a97b9 100644 --- a/tasks/SemaphoreIF.h +++ b/tasks/SemaphoreIF.h @@ -12,7 +12,8 @@ * A semaphore is a synchronization primitive. * See: https://en.wikipedia.org/wiki/Semaphore_(programming) * A semaphore can be used to achieve task synchonization and track the - * availability of resources. + * availability of resources by using either the binary or the counting + * semaphore types. * * If mutual exlcusion of a resource is desired, a mutex should be used, * which is a special form of a semaphore and has an own interface. @@ -29,7 +30,7 @@ public: 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); + static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3); /** * Generic call to acquire a semaphore. @@ -54,7 +55,7 @@ public: * is returned if the semaphore is available, and 0 is returned if the * semaphore is not available. */ - virtual uint8_t getSemaphoreCounter() = 0; + virtual uint8_t getSemaphoreCounter() const = 0; }; #endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */ -- 2.34.1