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_ */