From e26f0d54b2828e786c4d91ef38345a7e68d1fbcf Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:44:03 +0200 Subject: [PATCH 01/19] 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 00000000..b5f8e6c6 --- /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 00000000..2203c923 --- /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_ */ From 6eda5a08381891907d67e3b23a93e80808585b07 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:46:49 +0200 Subject: [PATCH 02/19] 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 00000000..fd2bfc0b --- /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_ */ From 1b5127dc85f236d7e02cdb22c722bea4976d531b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:50:07 +0200 Subject: [PATCH 03/19] 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 00000000..9946833d --- /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(); + } +} + + + From 0e6f8d3f821d3fa6907de2310e9102a33d30afb2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 22 Apr 2020 19:53:06 +0200 Subject: [PATCH 04/19] 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 9946833d..0c96c62f 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); From 328737d0ad5d6efb098963fdf0e5088776f50f64 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:12:02 +0200 Subject: [PATCH 05/19] 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 b5f8e6c6..a6a923aa 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 2203c923..0ab9cdea 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 From fc4199c3b12dfc6f7996d75c035fb0767c21a004 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 23 Apr 2020 18:13:14 +0200 Subject: [PATCH 06/19] 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 0c96c62f..d7ddaf38 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 fd2bfc0b..c122e0fb 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: /** From 1d4d01d1906d1300eb7fe4e65d259afe64210a81 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:22:10 +0200 Subject: [PATCH 07/19] 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 e5da0442..38f425a4 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 32f41b44..ce6ed46b 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 00000000..52222531 --- /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 00000000..eaaf97e2 --- /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_ */ From d1500a78685d18e05b94419be69f9cb09056c127 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:31:05 +0200 Subject: [PATCH 08/19] 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 38f425a4..12a3173a 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 ce6ed46b..c278e329 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; From f8614e23a867d21d64922329164920c41ab55c38 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:38:19 +0200 Subject: [PATCH 09/19] 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 12a3173a..9e4b581b 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 c278e329..e88bbcec 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_ */ From 41c0ca6c52a728ffaf359805efb0df0319b9dcc3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:39:10 +0200 Subject: [PATCH 10/19] 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 e88bbcec..07e95ddf 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); /** From b23728731548d900b97a70e3d32565ebcfcc50e7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 17:48:16 +0200 Subject: [PATCH 11/19] 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 a6a923aa..acfc53bd 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 d21861c0..120d8b8c 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 ! }; From 45b0193ef38b70a4f1d5be76564258bc6ab5c928 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 18:06:40 +0200 Subject: [PATCH 12/19] 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 0ab9cdea..865da8a6 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 { From 87bf843beffe92f7f535609cb83fcb4378f952be Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:19:50 +0200 Subject: [PATCH 13/19] 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 00000000..babac05a --- /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_ */ From 9ba21b1e288ba9f8e20fae9c4cc7ea6923b2651f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:30:50 +0200 Subject: [PATCH 14/19] semaphore if continued --- tasks/SemaphoreIF.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index babac05a..cf56f6f9 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_ */ From 4dd6594845deb381b80fcb2ba8e0ec27acec27e1 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:38:02 +0200 Subject: [PATCH 15/19] 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 acfc53bd..c0300b81 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 865da8a6..8271d9d0 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 cf56f6f9..616b992d 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_ */ From b1d9d55f50a0e242ec57604934659c7fff50eb01 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:05 +0200 Subject: [PATCH 16/19] improved documentation --- tasks/SemaphoreIF.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tasks/SemaphoreIF.h b/tasks/SemaphoreIF.h index 616b992d..7dde27f4 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: From 067cd9573100952c1398b956a8b7d2cbeab93a3a Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 19:42:45 +0200 Subject: [PATCH 17/19] 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 c0300b81..e4850702 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 8271d9d0..854cbba4 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; /** From 7227c3a8667a1ead8c4160b8372d350e79617de4 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:35:13 +0200 Subject: [PATCH 18/19] 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 e4850702..11e48153 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 854cbba4..6383432f 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 00000000..adf3f23c --- /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 00000000..8c059af5 --- /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 91f29585..ccbcad26 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 cadb54fb..08cd68c8 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 00000000..dd319025 --- /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 00000000..fa95399a --- /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_ */ From 066930b110730c8c781f0b680e1f7b99f1dbe920 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 18 May 2020 20:39:48 +0200 Subject: [PATCH 19/19] 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 11e48153..f08e3b81 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 6383432f..bd4ddb95 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 8c059af5..a33a0fa5 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 dd319025..9a355891 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,