diff --git a/ipc/MutexIF.h b/ipc/MutexIF.h index a4aff1cd8..dcb1cf333 100644 --- a/ipc/MutexIF.h +++ b/ipc/MutexIF.h @@ -13,7 +13,7 @@ class MutexIF { public: static const uint32_t NO_TIMEOUT; //!< Needs to be defined in implementation. - + static const uint32_t MAX_TIMEOUT; static const uint8_t INTERFACE_ID = CLASS_ID::MUTEX_IF; /** * The system lacked the necessary resources (other than memory) to initialize another mutex. 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/Clock.cpp b/osal/FreeRTOS/Clock.cpp index 5e597f258..dce202657 100644 --- a/osal/FreeRTOS/Clock.cpp +++ b/osal/FreeRTOS/Clock.cpp @@ -1,19 +1,18 @@ #include #include +#include + +#include +#include + #include -#include "Timekeeper.h" - -extern "C" { -#include -#include -} - +#include //TODO sanitize input? //TODO much of this code can be reused for tick-only systems uint16_t Clock::leapSeconds = 0; -MutexIF* Clock::timeMutex = NULL; +MutexIF* Clock::timeMutex = nullptr; uint32_t Clock::getTicksPerSecond(void) { return 1000; @@ -130,7 +129,7 @@ ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { //SHOULDDO: works not for dates in the past (might have less leap seconds) - if (timeMutex == NULL) { + if (timeMutex == nullptr) { return HasReturnvaluesIF::RETURN_FAILED; } 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 988733f6b..81b4c186d 100644 --- a/osal/FreeRTOS/MessageQueue.h +++ b/osal/FreeRTOS/MessageQueue.h @@ -6,11 +6,8 @@ #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 @@ -164,11 +161,7 @@ public: MessageQueueId_t getId() const; /** -<<<<<<< HEAD - * \brief This method is a simple setter for the default destination. -======= * @brief This method is a simple setter for the default destination. ->>>>>>> mueller_BinSempahInterface */ void setDefaultDestination(MessageQueueId_t defaultDestination); /** @@ -199,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); @@ -209,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/Mutex.cpp b/osal/FreeRTOS/Mutex.cpp index 25513a819..cc2f865ff 100644 --- a/osal/FreeRTOS/Mutex.cpp +++ b/osal/FreeRTOS/Mutex.cpp @@ -1,29 +1,33 @@ -#include "Mutex.h" +#include #include const uint32_t MutexIF::NO_TIMEOUT = 0; +const uint32_t MutexIF::MAX_TIMEOUT = portMAX_DELAY; Mutex::Mutex() { handle = xSemaphoreCreateMutex(); - if(handle == NULL) { - sif::error << "Mutex creation failure" << std::endl; + if(handle == nullptr) { + sif::error << "Mutex: Creation failure" << std::endl; } } Mutex::~Mutex() { - if (handle != 0) { + if (handle != nullptr) { vSemaphoreDelete(handle); } } ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { - if (handle == 0) { + if (handle == nullptr) { return MutexIF::MUTEX_NOT_FOUND; } - TickType_t timeout = portMAX_DELAY; - if (timeoutMs != NO_TIMEOUT) { + TickType_t timeout = MutexIF::NO_TIMEOUT; + if(timeoutMs == MutexIF::MAX_TIMEOUT) { + timeout = MutexIF::MAX_TIMEOUT; + } + else if(timeoutMs > MutexIF::NO_TIMEOUT){ timeout = pdMS_TO_TICKS(timeoutMs); } @@ -36,7 +40,7 @@ ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { } ReturnValue_t Mutex::unlockMutex() { - if (handle == 0) { + if (handle == nullptr) { return MutexIF::MUTEX_NOT_FOUND; } BaseType_t returncode = xSemaphoreGive(handle); diff --git a/osal/FreeRTOS/Mutex.h b/osal/FreeRTOS/Mutex.h index ef93fd344..90e824678 100644 --- a/osal/FreeRTOS/Mutex.h +++ b/osal/FreeRTOS/Mutex.h @@ -3,11 +3,8 @@ #include -extern "C" { #include #include -} - /** * @brief OS component to implement MUTual EXclusion @@ -21,7 +18,7 @@ class Mutex : public MutexIF { public: Mutex(); ~Mutex(); - ReturnValue_t lockMutex(uint32_t timeoutMs) override; + ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::MAX_TIMEOUT) override; ReturnValue_t unlockMutex() override; private: SemaphoreHandle_t handle; diff --git a/osal/FreeRTOS/SemaphoreFactory.cpp b/osal/FreeRTOS/SemaphoreFactory.cpp index 7bd71dd7a..05a898cd1 100644 --- a/osal/FreeRTOS/SemaphoreFactory.cpp +++ b/osal/FreeRTOS/SemaphoreFactory.cpp @@ -1,5 +1,7 @@ #include +#include #include +#include #include #include @@ -7,6 +9,9 @@ SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; const uint32_t SemaphoreIF::NO_TIMEOUT = 0; const uint32_t SemaphoreIF::MAX_TIMEOUT = portMAX_DELAY; +static const uint32_t USE_REGULAR_SEMAPHORES = 0; +static const uint32_t USE_TASK_NOTIFICATIONS = 1; + SemaphoreFactory::SemaphoreFactory() { } @@ -21,15 +26,36 @@ SemaphoreFactory* SemaphoreFactory::instance() { return SemaphoreFactory::factoryInstance; } -SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { - return new BinarySemaphore(); +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new BinarySemaphore(); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new BinarySemaphoreUsingTask(); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new BinarySemaphore(); + } } -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, - uint8_t initCount) { - return new CountingSemaphore(count, initCount); +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount, + uint8_t initCount, uint32_t argument) { + if(argument == USE_REGULAR_SEMAPHORES) { + return new CountingSemaphore(maxCount, initCount); + } + else if(argument == USE_TASK_NOTIFICATIONS) { + return new CountingSemaphoreUsingTask(maxCount, initCount); + } + else { + sif::warning << "SemaphoreFactory: Invalid argument, return regular" + "binary semaphore" << std::endl; + return new CountingSemaphore(maxCount, initCount); + } + } -void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { delete semaphore; } diff --git a/osal/FreeRTOS/TaskManagement.cpp b/osal/FreeRTOS/TaskManagement.cpp index 4529b3710..7871ab2ec 100644 --- a/osal/FreeRTOS/TaskManagement.cpp +++ b/osal/FreeRTOS/TaskManagement.cpp @@ -5,8 +5,8 @@ void TaskManagement::requestContextSwitchFromTask() { } 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 { diff --git a/osal/FreeRTOS/TaskManagement.h b/osal/FreeRTOS/TaskManagement.h index b9874db0c..39c24377b 100644 --- a/osal/FreeRTOS/TaskManagement.h +++ b/osal/FreeRTOS/TaskManagement.h @@ -21,9 +21,9 @@ extern "C" void requestContextSwitchFromISR(); * has different functions for handling semaphores and messages from within * 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 }; diff --git a/osal/FreeRTOS/Timekeeper.cpp b/osal/FreeRTOS/Timekeeper.cpp index 949e1df3c..643b27479 100644 --- a/osal/FreeRTOS/Timekeeper.cpp +++ b/osal/FreeRTOS/Timekeeper.cpp @@ -1,17 +1,12 @@ -/** - * @file Timekeeper.cpp - * @date - */ - #include -extern "C" { -#include -} +#include "FreeRTOSConfig.h" Timekeeper * Timekeeper::myinstance = nullptr; -Timekeeper::Timekeeper() : offset( { 0, 0 }) {} +Timekeeper::Timekeeper() : offset( { 0, 0 } ) {} + +Timekeeper::~Timekeeper() {} const timeval& Timekeeper::getOffset() const { return offset; @@ -28,8 +23,6 @@ void Timekeeper::setOffset(const timeval& offset) { this->offset = offset; } -Timekeeper::~Timekeeper() {} - timeval Timekeeper::ticksToTimeval(TickType_t ticks) { timeval uptime; uptime.tv_sec = ticks / configTICK_RATE_HZ; diff --git a/osal/FreeRTOS/Timekeeper.h b/osal/FreeRTOS/Timekeeper.h index 05f0f7011..7d3ca22b7 100644 --- a/osal/FreeRTOS/Timekeeper.h +++ b/osal/FreeRTOS/Timekeeper.h @@ -2,9 +2,9 @@ #define FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ #include -extern "C" { -#include -} + +#include +#include /** diff --git a/osal/linux/BinarySemaphore.cpp b/osal/linux/BinarySemaphore.cpp new file mode 100644 index 000000000..7c76a5c4f --- /dev/null +++ b/osal/linux/BinarySemaphore.cpp @@ -0,0 +1,148 @@ +#include +#include + +extern "C" { +#include +#include +} + +BinarySemaphore::BinarySemaphore() { + // Using unnamed semaphores for now + initSemaphore(); +} + +BinarySemaphore::~BinarySemaphore() { + sem_destroy(&handle); +} + +BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) { + initSemaphore(); +} + +BinarySemaphore& BinarySemaphore::operator =( + BinarySemaphore&& s) { + initSemaphore(); + return * this; +} + +ReturnValue_t BinarySemaphore::acquire(uint32_t timeoutMs) { + int result = 0; + if(timeoutMs == SemaphoreIF::NO_TIMEOUT) { + result = sem_trywait(&handle); + } + else if(timeoutMs == SemaphoreIF::MAX_TIMEOUT) { + result = sem_wait(&handle); + } + else if(timeoutMs > SemaphoreIF::NO_TIMEOUT){ + timespec timeOut; + clock_gettime(CLOCK_REALTIME, &timeOut); + uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec; + nseconds += timeoutMs * 1000000; + timeOut.tv_sec = nseconds / 1000000000; + timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000; + result = sem_timedwait(&handle, &timeOut); + if(result != 0 and errno == EINVAL) { + sif::debug << "BinarySemaphore::acquire: Invalid time value possible" + << std::endl; + } + } + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EAGAIN): + // Operation could not be performed without blocking (for sem_trywait) + case(ETIMEDOUT): + // Semaphore is 0 + return SemaphoreIF::SEMAPHORE_TIMEOUT; + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EINTR): + // Call was interrupted by signal handler + sif::debug << "BinarySemaphore::acquire: Signal handler interrupted." + "Code " << strerror(errno) << std::endl; + /* No break */ + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t BinarySemaphore::release() { + return BinarySemaphore::release(&this->handle); +} + +ReturnValue_t BinarySemaphore::release(sem_t *handle) { + ReturnValue_t countResult = checkCount(handle, 1); + if(countResult != HasReturnvaluesIF::RETURN_OK) { + return countResult; + } + + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t BinarySemaphore::getSemaphoreCounter() const { + // And another ugly cast :-D + return getSemaphoreCounter(const_cast(&this->handle)); +} + +uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) { + int value = 0; + int result = sem_getvalue(handle, &value); + if (result == 0) { + return value; + } + else if(result != 0 and errno == EINVAL) { + // Could be called from interrupt, use lightweight printf + printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n"); + return 0; + } + else { + // This should never happen. + return 0; + } +} + +void BinarySemaphore::initSemaphore(uint8_t initCount) { + auto result = sem_init(&handle, true, initCount); + if(result == -1) { + switch(errno) { + case(EINVAL): + // Value exceeds SEM_VALUE_MAX + case(ENOSYS): + // System does not support process-shared semaphores + sif::error << "BinarySemaphore: Init failed with" << strerror(errno) + << std::endl; + } + } +} + +ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) { + int value = getSemaphoreCounter(handle); + if(value >= maxCount) { + if(maxCount == 1 and value > 1) { + // Binary Semaphore special case. + // This is a config error use lightweight printf is this is called + // from an interrupt + printf("BinarySemaphore::release: Value of binary semaphore greater" + " than 1!\n"); + return HasReturnvaluesIF::RETURN_FAILED; + } + return SemaphoreIF::SEMAPHORE_NOT_OWNED; + } + return HasReturnvaluesIF::RETURN_OK; +} diff --git a/osal/linux/BinarySemaphore.h b/osal/linux/BinarySemaphore.h new file mode 100644 index 000000000..7836cd413 --- /dev/null +++ b/osal/linux/BinarySemaphore.h @@ -0,0 +1,81 @@ +#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ +#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_ + +#include +#include + +extern "C" { +#include +} + +/** + * @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 + * See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html + * @author R. Mueller + * @ingroup osal + */ +class BinarySemaphore: public SemaphoreIF, + public HasReturnvaluesIF { +public: + static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF; + + //! @brief Default ctor + 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 + BinarySemaphore & operator=(BinarySemaphore &&); + //! @brief Destructor + virtual ~BinarySemaphore(); + + void initSemaphore(uint8_t initCount = 1); + + uint8_t getSemaphoreCounter() const override; + static uint8_t getSemaphoreCounter(sem_t* handle); + + /** + * 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 SemaphoreIF::SEMAPHORE_TIMEOUT on timeout + */ + ReturnValue_t acquire(uint32_t timeoutMs = + SemaphoreIF::NO_TIMEOUT) override; + + /** + * Release the binary semaphore. + * @return -@c RETURN_OK on success + * -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is + * already available. + */ + virtual ReturnValue_t release() override; + /** + * This static function can be used to release a semaphore by providing + * its handle. + * @param handle + * @return + */ + static ReturnValue_t release(sem_t* handle); + + /** Checks the validity of the semaphore count against a specified + * known maxCount + * @param handle + * @param maxCount + * @return + */ + static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount); +protected: + sem_t handle; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */ diff --git a/osal/linux/Clock.cpp b/osal/linux/Clock.cpp index e24a4fe4b..630b2cf4c 100644 --- a/osal/linux/Clock.cpp +++ b/osal/linux/Clock.cpp @@ -1,10 +1,10 @@ -#include -#include +#include #include - +#include #include #include +#include #include //#include @@ -65,6 +65,15 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { return HasReturnvaluesIF::RETURN_OK; } +timeval Clock::getUptime() { + timeval uptime; + auto result = getUptime(&uptime); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Clock::getUptime: Error getting uptime" << std::endl; + } + return uptime; +} + ReturnValue_t Clock::getUptime(timeval* uptime) { //TODO This is not posix compatible and delivers only seconds precision struct sysinfo sysInfo; diff --git a/osal/linux/CountingSemaphore.cpp b/osal/linux/CountingSemaphore.cpp new file mode 100644 index 000000000..dfc4d8013 --- /dev/null +++ b/osal/linux/CountingSemaphore.cpp @@ -0,0 +1,54 @@ +#include +#include + +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; + } + + initSemaphore(initCount); +} + +CountingSemaphore::CountingSemaphore(CountingSemaphore&& other): + maxCount(other.maxCount), initCount(other.initCount) { + initSemaphore(initCount); +} + +CountingSemaphore& CountingSemaphore::operator =( + CountingSemaphore&& other) { + initSemaphore(other.initCount); + return * this; +} + +ReturnValue_t CountingSemaphore::release() { + ReturnValue_t result = checkCount(&handle, maxCount); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return CountingSemaphore::release(&this->handle); +} + +ReturnValue_t CountingSemaphore::release(sem_t* handle) { + int result = sem_post(handle); + if(result == 0) { + return HasReturnvaluesIF::RETURN_OK; + } + + switch(errno) { + case(EINVAL): + // Semaphore invalid + return SemaphoreIF::SEMAPHORE_INVALID; + case(EOVERFLOW): + // SEM_MAX_VALUE overflow. This should never happen + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +uint8_t CountingSemaphore::getMaxCount() const { + return maxCount; +} + diff --git a/osal/linux/CountingSemaphore.h b/osal/linux/CountingSemaphore.h new file mode 100644 index 000000000..ba6065955 --- /dev/null +++ b/osal/linux/CountingSemaphore.h @@ -0,0 +1,37 @@ +#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_ +#include + +/** + * @brief Counting semaphores, which can be acquired 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(const uint8_t maxCount, 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 &&); + + ReturnValue_t release() override; + static ReturnValue_t release(sem_t* sem); + /* 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: + const uint8_t maxCount; + uint8_t initCount = 0; +}; + +#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */ diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 96d9fb4d0..48ba29e80 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -7,7 +7,7 @@ #include -MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize) : +MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): id(0), lastPartner(0), defaultDestination(NO_QUEUE) { //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; mq_attr attributes; diff --git a/osal/linux/Mutex.h b/osal/linux/Mutex.h index 872ac3ac4..607337aea 100644 --- a/osal/linux/Mutex.h +++ b/osal/linux/Mutex.h @@ -1,5 +1,5 @@ -#ifndef OS_RTEMS_MUTEX_H_ -#define OS_RTEMS_MUTEX_H_ +#ifndef OS_LINUX_MUTEX_H_ +#define OS_LINUX_MUTEX_H_ #include diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index 28a0b9461..f6a74901c 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -57,9 +57,11 @@ void PeriodicPosixTask::taskFunctionality(void){ char name[20] = {0}; int status = pthread_getname_np(pthread_self(),name,sizeof(name)); if(status==0){ - sif::error << "ObjectTask: " << name << " Deadline missed." << std::endl; + sif::error << "PeriodicPosixTask " << name << ": Deadline " + "missed." << std::endl; }else{ - sif::error << "ObjectTask: X Deadline missed. " << status << std::endl; + sif::error << "PeriodicPosixTask X: Deadline missed. " << + status << std::endl; } if (this->deadlineMissedFunc != NULL) { this->deadlineMissedFunc(); diff --git a/osal/linux/SemaphoreFactory.cpp b/osal/linux/SemaphoreFactory.cpp index b1100e750..5aec84eae 100644 --- a/osal/linux/SemaphoreFactory.cpp +++ b/osal/linux/SemaphoreFactory.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include const uint32_t SemaphoreIF::NO_TIMEOUT = 0; @@ -20,18 +22,15 @@ SemaphoreFactory* SemaphoreFactory::instance() { return SemaphoreFactory::factoryInstance; } -SemaphoreIF* SemaphoreFactory::createBinarySemaphore() { - sif::error << "Semaphore not implemented for Linux yet" << std::endl; - return nullptr; +SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { + return new BinarySemaphore(); } -SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t count, - uint8_t initCount) { - sif::error << "Counting Semaphore not implemented for " - "Linux yet" << std::endl; - return nullptr; +SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, + uint8_t initCount, uint32_t arguments) { + return new CountingSemaphore(maxCount, initCount); } -void SemaphoreFactory::deleteMutex(SemaphoreIF* semaphore) { +void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { delete semaphore; } diff --git a/storagemanager/LocalPool.h b/storagemanager/LocalPool.h index c155f918b..2d61dea51 100644 --- a/storagemanager/LocalPool.h +++ b/storagemanager/LocalPool.h @@ -22,6 +22,7 @@ * 0xFFFF-1 bytes. * It is possible to store empty packets in the pool. * The local pool is NOT thread-safe. + * @author Bastian Baetz */ template diff --git a/storagemanager/LocalPool.tpp b/storagemanager/LocalPool.tpp index 32724bd8c..764bd7be4 100644 --- a/storagemanager/LocalPool.tpp +++ b/storagemanager/LocalPool.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ #define FRAMEWORK_STORAGEMANAGER_LOCALPOOL_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_LOCALPOOL_H_ +#error Include LocalPool.h before LocalPool.tpp! +#endif + template inline LocalPool::LocalPool(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], diff --git a/storagemanager/PoolManager.h b/storagemanager/PoolManager.h index 6e353de22..c74e95c0e 100644 --- a/storagemanager/PoolManager.h +++ b/storagemanager/PoolManager.h @@ -10,6 +10,7 @@ * a fixed pool size policy for inter-process communication. * @details Uses local pool calls but is thread safe by protecting the call * with a lock. + * @author Bastian Baetz */ template class PoolManager : public LocalPool { diff --git a/storagemanager/PoolManager.tpp b/storagemanager/PoolManager.tpp index 854e22daa..29b2b82a6 100644 --- a/storagemanager/PoolManager.tpp +++ b/storagemanager/PoolManager.tpp @@ -1,6 +1,10 @@ #ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ #define FRAMEWORK_STORAGEMANAGER_POOLMANAGER_TPP_ +#ifndef FRAMEWORK_STORAGEMANAGER_POOLMANAGER_H_ +#error Include PoolManager.h before PoolManager.tpp! +#endif + template inline PoolManager::PoolManager(object_id_t setObjectId, const uint16_t element_sizes[NUMBER_OF_POOLS], 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_ */ diff --git a/timemanager/Clock.h b/timemanager/Clock.h index 5f18de3ee..19991b817 100644 --- a/timemanager/Clock.h +++ b/timemanager/Clock.h @@ -2,13 +2,14 @@ #define FRAMEWORK_TIMEMANAGER_CLOCK_H_ #include -#include -#include #include #include +#include +#include + typedef uint32_t millis_t; -typedef float seconds_t; +typedef double seconds_t; class Clock { public: @@ -22,7 +23,7 @@ public: uint32_t usecond; //!< Microseconds, 0 .. 999999 } TimeOfDay_t; - /**static Clock* TimeOfDay_t(); + /** * This method returns the number of clock ticks per second. * In RTEMS, this is typically 1000. * @return The number of ticks. @@ -34,22 +35,23 @@ public: * This system call sets the system time. * To set the time, it uses a TimeOfDay_t struct. * @param time The struct with the time settings to set. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code + * is returned. */ static ReturnValue_t setClock(const TimeOfDay_t* time); /** * This system call sets the system time. * To set the time, it uses a timeval struct. * @param time The struct with the time settings to set. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return -@c RETURN_OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t setClock(const timeval* time); /** * This system call returns the current system clock in timeval format. - * The timval format has the fields \c tv_sec with seconds and \c tv_usec with + * The timval format has the fields @c tv_sec with seconds and @c tv_usec with * microseconds since an OS-defined epoch. * @param time A pointer to a timeval struct where the current time is stored. - * @return \c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t getClock_timeval(timeval* time); @@ -57,7 +59,7 @@ public: * Get the time since boot in a timeval struct * * @param[out] time A pointer to a timeval struct where the uptime is stored. - * @return\c RETURN_OK on success. Otherwise, the OS failure code is returned. + * @return @c RETURN_OK on success. Otherwise, the OS failure code is returned. * * @deprecated, I do not think this should be able to fail, use timeval getUptime() */ diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index 1f287fb38..bc8b4149c 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -1,9 +1,3 @@ -/** - * @file Stopwatch.cpp - * - * @date 08.04.2020 - */ - #include #include #include @@ -12,11 +6,11 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode): displayOnDestruction( displayOnDestruction), displayMode(displayMode) { // Measures start time on initialization. - startTime = Clock::getUptime(); + Clock::getClock_timeval(&startTime); } void Stopwatch::start() { - startTime = Clock::getUptime(); + Clock::getClock_timeval(&startTime); } millis_t Stopwatch::stop() { @@ -57,5 +51,7 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { } void Stopwatch::stopInternal() { - elapsedTime = Clock::getUptime() - startTime; + timeval endTime; + Clock::getClock_timeval(&endTime); + elapsedTime = endTime - startTime; } diff --git a/timemanager/Stopwatch.h b/timemanager/Stopwatch.h index f48c04eca..71580778f 100644 --- a/timemanager/Stopwatch.h +++ b/timemanager/Stopwatch.h @@ -1,9 +1,3 @@ -/** - * @file Stopwatch.h - * - * @date 08.04.2020 - */ - #ifndef FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #define FRAMEWORK_TIMEMANAGER_STOPWATCH_H_ #include @@ -14,12 +8,13 @@ enum class StopwatchDisplayMode { }; /** - * @brief Simple Stopwatch implementation to measure elapsed time + * @brief Simple Stopwatch implementation to measure elapsed time * @details * This class can be used to measure elapsed times. It also displays elapsed * times automatically on destruction if not explicitely deactivated in the * constructor. The default time format is the elapsed time in miliseconds - * as a float. + * in seconds as a double. + * @author R. Mueller */ class Stopwatch { public: @@ -46,6 +41,10 @@ public: * @return elapsed time in milliseconds (rounded) */ millis_t stop(); + /** + * Calculates the elapsed time since start and returns it + * @return elapsed time in seconds (double precision) + */ seconds_t stopSeconds(); /**