adding freeRtos API from different project
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file mutex.hpp
|
||||
* @author Gustice
|
||||
* @brief Mutex Wrapper
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
namespace fos {
|
||||
|
||||
/**
|
||||
* @brief Mutex
|
||||
* @details FreeRTOS implementation uses already priority inheritance
|
||||
* and are recursively callable
|
||||
*/
|
||||
class Mutex {
|
||||
private:
|
||||
QueueHandle_t _handle;
|
||||
|
||||
public:
|
||||
/// @brief Tick type (redefinition for convenience)
|
||||
using Tick = TickType_t;
|
||||
/// @brief Definition for endless waittime
|
||||
static constexpr Tick MaxDelay = portMAX_DELAY;
|
||||
|
||||
/// @brief Constructor
|
||||
Mutex() {
|
||||
_handle = xSemaphoreCreateMutex();
|
||||
assert(_handle != 0 && "Semaphore create must finish successfully");
|
||||
}
|
||||
|
||||
~Mutex() {
|
||||
vSemaphoreDelete(_handle);
|
||||
};
|
||||
|
||||
/// @brief Relase mutex
|
||||
void release() {
|
||||
auto ret = xSemaphoreGive(_handle);
|
||||
assert(ret == pdPASS && "Underlying semaphore queue must be initialized correcty");
|
||||
}
|
||||
|
||||
/// @brief Take mutex
|
||||
/// @param timeout Timeout to wait for signal (default = wait forever)
|
||||
/// @return true if successfully claimed (not timeout)
|
||||
bool claim(Tick timeout = MaxDelay) {
|
||||
auto ret = xSemaphoreTake(_handle, timeout);
|
||||
return ret == pdPASS;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Mutex Guard. Self releasing mutex for atomic operation
|
||||
*/
|
||||
class MutexGuard {
|
||||
private:
|
||||
Mutex &_mutex;
|
||||
bool _claimed;
|
||||
|
||||
public:
|
||||
/// @brief Constructor
|
||||
/// @param mtx Mutex to claim
|
||||
/// @param timeout Timeout to wait for signal (default = wait forever)
|
||||
MutexGuard(Mutex &mtx, Mutex::Tick timeout = Mutex::MaxDelay) : _mutex(mtx) {
|
||||
_claimed = _mutex.claim(timeout);
|
||||
};
|
||||
|
||||
~MutexGuard() {
|
||||
if (!_claimed) {
|
||||
return;
|
||||
}
|
||||
|
||||
_mutex.release();
|
||||
}
|
||||
|
||||
/// @brief Check if mutex was claimed successfully
|
||||
/// @return true if claimed
|
||||
bool isActive() {
|
||||
return _claimed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fos
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file queue.hpp
|
||||
* @author Gustice
|
||||
* @brief Queue Wrapper
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace fos {
|
||||
|
||||
/**
|
||||
* @brief Message Queue
|
||||
*
|
||||
* @tparam T Type for message payload
|
||||
*/
|
||||
template <typename T>
|
||||
class Queue {
|
||||
private:
|
||||
bool _isActive;
|
||||
QueueHandle_t xQueue;
|
||||
|
||||
public:
|
||||
/// @brief Tick type (redefinition for convenience)
|
||||
using Tick = TickType_t;
|
||||
/// @brief Definition for endless waittime
|
||||
static constexpr Tick MaxDelay = portMAX_DELAY;
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param size number of slots in queue
|
||||
Queue(size_t size) {
|
||||
xQueue = xQueueCreate(size, sizeof(T *));
|
||||
assert(xQueue != 0 && "Queue create must finish successfully");
|
||||
_isActive = true;
|
||||
}
|
||||
|
||||
~Queue() {
|
||||
vQueueDelete(xQueue);
|
||||
}
|
||||
|
||||
/// @brief Push new message in queue
|
||||
/// @param message payload
|
||||
/// @return nullptr if successful else give back pointer to queued element if pushing failed
|
||||
std::unique_ptr<T> enqueue(std::unique_ptr<T> message) {
|
||||
if (uxQueueSpacesAvailable(xQueue) == 0) {
|
||||
return message;
|
||||
}
|
||||
T *o = message.release();
|
||||
auto ret = xQueueSend(xQueue, &o, (TickType_t)0);
|
||||
assert(ret == pdPASS && "Underlying semaphore queue must be initialized correcty");
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/// @brief Pop message from queue
|
||||
/// @param timeout timeout to wait for message (default: wait for ever)
|
||||
/// @return pointer to dequeued element
|
||||
std::unique_ptr<T> dequeue(Tick timeout = MaxDelay) {
|
||||
T *pMsg = nullptr;
|
||||
if (!xQueueReceive(xQueue, &pMsg, timeout)) {
|
||||
return {nullptr};
|
||||
}
|
||||
return std::unique_ptr<T>(pMsg);
|
||||
}
|
||||
|
||||
/// @brief Pop latest element from queue and ignore all older elements
|
||||
/// @param timeout timeout to wait for message (default: wait for ever)
|
||||
/// @return pointer to dequeued element
|
||||
std::unique_ptr<T> dequeueLatest(Tick timeout = MaxDelay) {
|
||||
T *pMsg = nullptr;
|
||||
if (!xQueueReceive(xQueue, &pMsg, timeout)) {
|
||||
return {nullptr};
|
||||
}
|
||||
|
||||
while (true == xQueueReceive(xQueue, &pMsg, (TickType_t)0)) {
|
||||
}
|
||||
return std::unique_ptr<T>(pMsg);
|
||||
}
|
||||
|
||||
/// @brief terminate message queue
|
||||
void signalClose() {
|
||||
_isActive = false;
|
||||
}
|
||||
|
||||
/// @brief Check if message queue is active
|
||||
/// @return true if active
|
||||
bool isActive() {
|
||||
return _isActive;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fos
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file semaphore.hpp
|
||||
* @author Gustice
|
||||
* @brief Semaphore Wrapper
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
namespace fos {
|
||||
|
||||
/**
|
||||
* @brief Semaphore
|
||||
*/
|
||||
class Semaphore {
|
||||
private:
|
||||
enum Type {
|
||||
Binary, ///< Binary semaphore, can only be true or false, no matter how often given
|
||||
Counting ///< Counting semaphore, keeps track of number of give and takes
|
||||
};
|
||||
|
||||
const Type SemType;
|
||||
QueueHandle_t _handle;
|
||||
|
||||
public:
|
||||
/// @brief Tick type (redefinition for convenience)
|
||||
using Tick = TickType_t;
|
||||
|
||||
/// @brief Definition for endless waittime
|
||||
static constexpr Tick MaxDelay = portMAX_DELAY;
|
||||
|
||||
/// @brief Constructor for binary semaphore
|
||||
Semaphore() : SemType(Semaphore::Binary) {
|
||||
_handle = xSemaphoreCreateBinary();
|
||||
assert(_handle != 0 && "Semaphore create must finish successfully");
|
||||
}
|
||||
|
||||
/// @brief Constructor for conting semaphore
|
||||
/// @param maxCount Counting limit
|
||||
/// @param init Initial count
|
||||
Semaphore(uint32_t maxCount, uint32_t init = 0) : SemType(Semaphore::Counting) {
|
||||
_handle = xSemaphoreCreateCounting(maxCount, init);
|
||||
assert(_handle != 0 && "Semaphore create must finish successfully");
|
||||
}
|
||||
|
||||
~Semaphore() {
|
||||
vSemaphoreDelete(_handle);
|
||||
};
|
||||
|
||||
/// @brief Give signal
|
||||
/// @note Binary semaphore can only be effectively given once
|
||||
void give() {
|
||||
// checking for error would lead to false positives in case of multiple gives ...
|
||||
xSemaphoreGive(_handle);
|
||||
}
|
||||
|
||||
/// @brief Consume signal
|
||||
/// @param timeout Timeout to wait for signal (default = wait forever)
|
||||
/// @return true if successfully consumed (not timeout)
|
||||
bool take(Tick timeout = MaxDelay) {
|
||||
auto ret = xSemaphoreTake(_handle, timeout);
|
||||
return ret == pdPASS;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fos
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* @file task.hpp
|
||||
* @author Gustice
|
||||
* @brief Task Wrapper
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <cassert>
|
||||
#include <string_view>
|
||||
#include <Semaphore.hpp>
|
||||
#define DEFAULT_STACKSIZE 0x1000uL
|
||||
|
||||
namespace fos {
|
||||
/**
|
||||
* @brief Base class for tasks
|
||||
*/
|
||||
class TaskBase {
|
||||
protected:
|
||||
TaskHandle_t _handle;
|
||||
|
||||
static void disposeFrameConditionally() {
|
||||
if constexpr (INCLUDE_vTaskDelete != 0) {
|
||||
vTaskDelete(NULL);
|
||||
// NOTE: This only compiles if symbol INCLUDE_vTaskDelete is defined
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore _finished;
|
||||
|
||||
public:
|
||||
/// @brief Priority type (redefinition for convenience)
|
||||
using Priority = unsigned short;
|
||||
/// @brief Tick type (redefinition for convenience)
|
||||
using Tick = TickType_t;
|
||||
/// @brief Definition for endless waittime
|
||||
static constexpr Tick MaxDelay = portMAX_DELAY;
|
||||
|
||||
/// @brief Maximum delay
|
||||
static constexpr int MaximumDelay = portMAX_DELAY;
|
||||
|
||||
/// @brief Default Stack size
|
||||
static constexpr size_t DefaultStackSize = DEFAULT_STACKSIZE;
|
||||
|
||||
/// @brief Lowest priority for new tasks
|
||||
static constexpr Priority MIN_PRIORITY = tskIDLE_PRIORITY + 1;
|
||||
|
||||
/// @brief Highest priority for new tasks
|
||||
static constexpr Priority MAX_PRIORITY = configMAX_PRIORITIES;
|
||||
|
||||
/// @brief Kill a task
|
||||
/// @note It can lead to undefined behaviour when one task deletes another task on a
|
||||
/// multi-core system. Hence a task should clear itself.
|
||||
void kill() { // NOTE: this leads to undefined behavior if interferes with Destructor
|
||||
vTaskDelete(_handle);
|
||||
}
|
||||
|
||||
/// @brief Join threads
|
||||
/// @param timeout timeout to wait for join else kill
|
||||
/// @return joined successfully
|
||||
bool join(Tick timeout = MaxDelay) {
|
||||
auto success = _finished.take(timeout);
|
||||
if(not success) {
|
||||
kill();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/// @brief Get task state
|
||||
/// @return FreeRTOS Task state
|
||||
eTaskState getState() {
|
||||
return eTaskGetState(_handle);
|
||||
}
|
||||
|
||||
/// @brief Get task handle
|
||||
/// @return FreeRTOS Task handle
|
||||
TaskHandle_t getHandle() {
|
||||
return _handle;
|
||||
}
|
||||
|
||||
/// @brief Delay function
|
||||
/// @param msToDelay Milliseconds to delay
|
||||
/// @note The minimal resolution for the delay is tick based
|
||||
static void delayMs(unsigned int msToDelay) {
|
||||
// pdMS_TO_TICKS(_timeout)
|
||||
vTaskDelay(msToDelay / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/// @brief Delay function
|
||||
/// @param ticksToDelay Ticks to delay
|
||||
static void delayTicks(unsigned int ticksToDelay) {
|
||||
vTaskDelay(ticksToDelay);
|
||||
}
|
||||
|
||||
virtual ~TaskBase() {
|
||||
kill();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple task without task parameter
|
||||
*/
|
||||
class Task : public TaskBase {
|
||||
private:
|
||||
/// @brief Signature for task-implementation-callback
|
||||
using TaskSignature = void (*)();
|
||||
|
||||
static void TaskFrame(void *_this) {
|
||||
auto &task = *reinterpret_cast<Task *>(_this);
|
||||
task._call();
|
||||
// Tasks shall not return, however if this happens dispose task
|
||||
disposeFrameConditionally();
|
||||
task._finished.give();
|
||||
}
|
||||
|
||||
TaskSignature _call;
|
||||
|
||||
public:
|
||||
/// @brief Constructor for task without passed argument
|
||||
/// @param call Function pointer to implementation
|
||||
/// @param name Name of task
|
||||
/// @param stack Stacksize if not default
|
||||
/// @param prio Priority if not default
|
||||
Task(TaskSignature call, const char *name, size_t stack = DefaultStackSize,
|
||||
Priority prio = MIN_PRIORITY)
|
||||
: _call{call} {
|
||||
auto ret = xTaskCreate(TaskFrame, name, stack, this, MIN_PRIORITY, &_handle);
|
||||
assert(pdPASS == ret && "Task create must finish successfully");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Task with task parameter
|
||||
* @tparam T Type of task parameter on call
|
||||
*/
|
||||
template <typename T>
|
||||
class TaskT : public TaskBase {
|
||||
private:
|
||||
/// @brief Signature for task-implementation-callback
|
||||
using TaskSignature = void (*)(T);
|
||||
|
||||
template <typename TS>
|
||||
struct Param {
|
||||
TaskSignature call;
|
||||
const TS &arg;
|
||||
};
|
||||
Param<T> _param;
|
||||
|
||||
static void TaskFrame(void *_this) {
|
||||
auto &task = *reinterpret_cast<TaskT *>(_this);
|
||||
auto ¶m = task._param;
|
||||
param.call(param.arg);
|
||||
// Tasks shall not return, however if this happens dispose task
|
||||
disposeFrameConditionally();
|
||||
task._finished.give();
|
||||
}
|
||||
|
||||
public:
|
||||
/// @brief Constructor for task with passed argument
|
||||
/// @param call Function pointer to implementation
|
||||
/// @param param Parameter ot pass task implementation
|
||||
/// @param name Name of task
|
||||
/// @param stack Stacksize if not default
|
||||
/// @param prio Priority if not default
|
||||
TaskT(TaskSignature call, const T ¶m, const char *name, size_t stack = DefaultStackSize,
|
||||
Priority prio = MIN_PRIORITY)
|
||||
: _param{call, param} {
|
||||
auto ret = xTaskCreate(TaskFrame, name, stack, this, MIN_PRIORITY, &_handle);
|
||||
assert(pdPASS == ret && "Task create must finish successfully");
|
||||
}
|
||||
};
|
||||
|
||||
class Timing {
|
||||
public:
|
||||
static uint32_t getTickCount() {
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fos
|
||||
Reference in New Issue
Block a user