updates: improvements across the board

This commit is contained in:
Robin Müller 2020-05-29 13:23:52 +02:00
parent c2d758eb96
commit a64813e9fc
14 changed files with 505 additions and 154 deletions

View File

@ -0,0 +1,91 @@
#include <framework/osal/FreeRTOS/BinSemaphUsingTask.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
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, &notificationValue);
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, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}

View File

@ -0,0 +1,75 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/tasks/SemaphoreIF.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* @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_ */

View File

@ -1,6 +1,5 @@
#include <framework/osal/FreeRTOS/BinarySemaphore.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
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;
}
}

View File

@ -3,16 +3,10 @@
#include <framework/returnvalues/HasReturnvaluesIF.h>
#include <framework/tasks/SemaphoreIF.h>
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
}
// 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;
};

View File

@ -0,0 +1,110 @@
#include <framework/osal/FreeRTOS/CountingSemaphUsingTask.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
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, &notificationValue);
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, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}
uint8_t CountingSemaphoreUsingTask::getMaxCount() const {
return maxCount;
}

View File

@ -0,0 +1,100 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#include <framework/osal/FreeRTOS/CountingSemaphUsingTask.h>
#include <framework/tasks/SemaphoreIF.h>
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
/**
* @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_ */

View File

@ -1,18 +1,28 @@
#include <framework/osal/FreeRTOS/CountingSemaphore.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
#include <freertos/semphr.h>
// 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;
}

View File

@ -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;
};

View File

@ -1,4 +1,4 @@
#include "MessageQueue.h"
#include <framework/osal/FreeRTOS/MessageQueue.h>
#include <framework/serviceinterface/ServiceInterfaceStream.h>
@ -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<QueueHandle_t>(sendTo),
static_cast<const void*>(message->getBuffer()), 0);
}

View File

@ -6,13 +6,12 @@
#include <framework/ipc/MessageQueueMessage.h>
#include <framework/osal/FreeRTOS/TaskManagement.h>
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
}
//TODO this class assumes that MessageQueueId_t is the same size as void* (the FreeRTOS handle type), compiler will catch this but it might be nice to have something checking or even an always working solution
// TODO: this class assumes that MessageQueueId_t is the same size as void*
// (the FreeRTOS handle type), compiler will catch this but it might be nice
// to have something checking or even an always working solution
// https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/
/**
@ -193,7 +192,7 @@ protected:
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessage* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false, CallContext callContext = CallContext::task);
bool ignoreFault=false, CallContext callContext = CallContext::TASK);
static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
@ -203,7 +202,7 @@ private:
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
//!< Stores the current system context
CallContext callContext = CallContext::task;
CallContext callContext = CallContext::TASK;
};
#endif /* MESSAGEQUEUE_H_ */

View File

@ -3,10 +3,10 @@
void TaskManagement::requestContextSwitchFromTask() {
vTaskDelay(0);
}
void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::task) {
if(callContext == CallContext::isr) {
CallContext callContext = CallContext::TASK) {
if(callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device
requestContextSwitchFromISR();
} else {
@ -20,4 +20,4 @@ TaskHandle_t TaskManagement::getCurrentTaskHandle() {
configSTACK_DEPTH_TYPE TaskManagement::getTaskStackHighWatermark() {
return uxTaskGetStackHighWaterMark(TaskManagement::getCurrentTaskHandle());
}
}

View File

@ -17,31 +17,30 @@ extern "C" void requestContextSwitchFromISR();
/*!
* Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS
* within an ISR or from a regular task. This is required because FreeRTOS
* has different functions for handling semaphores and messages from within
* an ISR and task.
* an ISR and task.
*/
enum CallContext {
task = 0x00,//!< task_context
isr = 0xFF //!< isr_context
enum class CallContext {
TASK = 0x00,//!< task_context
ISR = 0xFF //!< isr_context
};
class TaskManagement {
public:
/**
/**
* @brief In this function, a function dependant on the portmacro.h header
* function calls to request a context switch can be specified.
* This can be used if sending to the queue from an ISR caused a task
* to unblock and a context switch is required.
* to unblock and a context switch is required.
*/
static void requestContextSwitch(CallContext callContext);
/**
* If task preemption in FreeRTOS is disabled, a context switch
* can be requested manually by calling this function.
*/
*/
static void requestContextSwitchFromTask(void);
/**
@ -57,7 +56,7 @@ public:
* E.g. on a 32 bit machine, a value of 200 means 800 bytes.
* @return Smallest value of stack remaining since the task was started in
* words.
*/
*/
static configSTACK_DEPTH_TYPE getTaskStackHighWatermark();
};

View File

@ -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:
/**

View File

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