freertos/Demo/Common/include/FreeRTOS/Queue.hpp

738 lines
24 KiB
C++

/*
* FreeRTOS-Cpp
* Copyright (C) 2021 Jon Enz. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* https://github.com/jonenz/FreeRTOS-Cpp
*/
#ifndef FREERTOS_QUEUE_HPP
#define FREERTOS_QUEUE_HPP
#include <optional>
#include "FreeRTOS.h"
#include "queue.h"
namespace FreeRTOS {
/**
* @class QueueBase Queue.hpp <FreeRTOS/Queue.hpp>
*
* @brief Base class that provides the standard queue interface to
* FreeRTOS::Queue and FreeRTOS::StaticQueue.
*
* @note This class is not intended to be instantiated by the user. Use
* FreeRTOS::Queue or FreeRTOS::StaticQueue.
*
* @tparam T Type to be stored in the queue.
*/
template <class T>
class QueueBase {
public:
template <class>
friend class Queue;
template <class, UBaseType_t>
friend class StaticQueue;
QueueBase(const QueueBase&) = delete;
QueueBase& operator=(const QueueBase&) = delete;
static void* operator new(size_t, void* ptr) { return ptr; }
static void* operator new[](size_t, void* ptr) { return ptr; }
static void* operator new(size_t) = delete;
static void* operator new[](size_t) = delete;
/**
* Queue.hpp
*
* @brief Function that checks if the underlying queue handle is not NULL.
* This should be used to ensure a queue has been created correctly.
*
* @retval true the handle is not NULL.
* @retval false the handle is NULL.
*/
inline bool isValid() const { return (handle != NULL); }
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToBack( xQueue, pvItemToQueue,
* xTicksToWait )</tt>
*
* @see <https://www.freertos.org/a00117.html>
*
* Post an item to the back of a queue. The item is queued by copy, not by
* reference. This function must not be called from an interrupt service
* routine. See FreeRTOS::Queue::sendToBackFromISR() for an alternative which
* may be used in an ISR.
*
* @param item A reference to the item that is to be placed on the queue.
* @param ticksToWait The maximum amount of time the task should block waiting
* for space to become available on the queue, should it already be full. The
* call will return immediately if this is set to 0 and the queue is full. The
* time is defined in tick periods so the constant portTICK_PERIOD_MS should
* be used to convert to real time if this is required.
* @retval true if the item was successfully posted.
* @retval false otherwise.
*
* <b>Example Usage</b>
* @include Queue/sendToBack.cpp
*/
inline bool sendToBack(const T& item,
const TickType_t ticksToWait = portMAX_DELAY) const {
return (xQueueSendToBack(handle, &item, ticksToWait) == pdTRUE);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToBackFromISR( xQueue,
* pvItemToQueue, pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueSendToBackFromISR.html>
*
* @param higherPriorityTaskWoken A reference that will be set to true if
* sending to the queue caused a task to unblock, and the unblocked task has a
* priority higher than the currently running task.
* @param item A reference to the item that is to be placed on the queue.
* @retval true if the item was successfully posted
* @retval false otherwise.
*
* <b>Example Usage</b>
* @include Queue/sendToBackFromISR.cpp
*/
inline bool sendToBackFromISR(bool& higherPriorityTaskWoken,
const T& item) const {
BaseType_t taskWoken = pdFALSE;
bool result =
(xQueueSendToBackFromISR(handle, &item, &taskWoken) == pdPASS);
if (taskWoken == pdTRUE) {
higherPriorityTaskWoken = true;
}
return result;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToBackFromISR( xQueue,
* pvItemToQueue, pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueSendToBackFromISR.html>
*
* @overload
*/
inline bool sendToBackFromISR(const T& item) const {
return (xQueueSendToBackFromISR(handle, &item, NULL) == pdPASS);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToFront( xQueue, pvItemToQueue,
* xTicksToWait )</tt>
*
* @see <https://www.freertos.org/xQueueSendToFront.html>
*
* @param item A reference to the item that is to be placed on the queue.
* @param ticksToWait The maximum amount of time the task should block waiting
* for space to become available on the queue, should it already be full. The
* call will return immediately if this is set to 0 and the queue is full. The
* time is defined in tick periods so the constant portTICK_PERIOD_MS should
* be used to convert to real time if this is required.
* @retval true if the item was successfully posted.
* @retval false otherwise.
*
* <b>Example Usage</b>
* @include Queue/sendToFront.cpp
*/
inline bool sendToFront(const T& item,
const TickType_t ticksToWait = portMAX_DELAY) const {
return (xQueueSendToFront(handle, &item, ticksToWait) == pdTRUE);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToFrontFromISR( xQueue,
* pvItemToQueue, pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueSendToFrontFromISR.html>
*
* @param higherPriorityTaskWoken A reference that will be set to true if
* sending to the queue caused a task to unblock, and the unblocked task has a
* priority higher than the currently running task.
* @param item A reference to the item that is to be placed on the queue.
* @retval true if the item was successfully posted
* @retval false otherwise.
*
* <b>Example Usage</b>
* @include Queue/sendToFrontFromISR.cpp
*/
inline bool sendToFrontFromISR(bool& higherPriorityTaskWoken,
const T& item) const {
BaseType_t taskWoken = pdFALSE;
bool result =
(xQueueSendToFrontFromISR(handle, &item, &taskWoken) == pdPASS);
if (taskWoken == pdTRUE) {
higherPriorityTaskWoken = true;
}
return result;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>xQueueSendToFrontFromISR( xQueue,
* pvItemToQueue, pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueSendToFrontFromISR.html>
*
* @overload
*/
inline bool sendToFrontFromISR(const T& item) const {
return (xQueueSendToFrontFromISR(handle, &item, NULL) == pdPASS);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueReceive( QueueHandle_t
* xQueue, void *pvBuffer, TickType_t xTicksToWait )</tt>
*
* @see <https://www.freertos.org/a00118.html>
*
* Receive an item from a queue. This function must not be used in an
* interrupt service routine. See receiveFromISR() for an alternative that
* can.
*
* @param ticksToWait The maximum amount of time the task should block waiting
* for an item to receive should the queue be empty at the time of the call.
* Setting ticksToWait to 0 will cause the function to return immediately if
* the queue is empty. The time is defined in tick periods so the constant
* portTICK_PERIOD_MS should be used to convert to real time if this is
* required.
* @return std::optional<T> Object from the queue. User should check that the
* value is present.
*
* <b>Example Usage</b>
* @include Queue/receive.cpp
*/
inline std::optional<T> receive(
const TickType_t ticksToWait = portMAX_DELAY) const {
T buffer;
return (xQueueReceive(handle, &buffer, ticksToWait) == pdTRUE)
? std::optional<T>(buffer)
: std::nullopt;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueReceiveFromISR(
* QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken
* )</tt>
*
* @see <https://www.freertos.org/a00120.html>
*
* Receive an item from a queue. It is safe to use this function from within
* an interrupt service routine.
*
* @param higherPriorityTaskWoken A reference that will be set to true if
* sending to the queue caused a task to unblock, and the unblocked task has a
* priority higher than the currently running task.
* @return std::optional<T> Object from the queue. User should check that the
* value is present.
*
* <b>Example Usage</b>
* @include Queue/receiveFromISR.cpp
*/
inline std::optional<T> receiveFromISR(bool& higherPriorityTaskWoken) const {
T buffer;
BaseType_t taskWoken = pdFALSE;
bool result = (xQueueReceiveFromISR(handle, &buffer, &taskWoken) == pdTRUE);
if (taskWoken == pdTRUE) {
higherPriorityTaskWoken = true;
}
return result ? std::optional<T>(buffer) : std::nullopt;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueReceiveFromISR(
* QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken
* )</tt>
*
* @see <https://www.freertos.org/a00120.html>
*
* @overload
*/
inline std::optional<T> receiveFromISR() const {
T buffer;
return (xQueueReceiveFromISR(handle, &buffer, NULL) == pdTRUE)
? std::optional<T>(buffer)
: std::nullopt;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>UBaseType_t uxQueueMessagesWaiting(
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#ucQueueMessagesWaiting>
*
* Return the number of messages stored in a queue.
*
* @retval UBaseType_t The number of messages available in the queue.
*/
inline UBaseType_t messagesWaiting() const {
return uxQueueMessagesWaiting(handle);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>UBaseType_t uxQueueMessagesWaitingFromISR(
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#ucQueueMessagesWaitingFromISR>
*
* A version of messagesWaiting() that can be called from an ISR. Return the
* number of messages stored in a queue.
*
* @retval UBaseType_t The number of messages available in the queue.
*/
inline UBaseType_t messagesWaitingFromISR() const {
return uxQueueMessagesWaitingFromISR(handle);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>UBaseType_t uxQueueSpacesAvailable(
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#uxQueueSpacesAvailable>
*
* Return the number of free spaces in a queue.
*
* @retval UBaseType_t The number of free spaces available in the queue.
*/
inline UBaseType_t spacesAvailable() const {
return uxQueueSpacesAvailable(handle);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueReset( QueueHandle_t xQueue
* )</tt>
*
* @see <https://www.freertos.org/a00018.html#xQueueReset>
*
* Resets a queue to its original empty state.
*/
inline void reset() const { xQueueReset(handle); }
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueOverwrite( QueueHandle_t
* xQueue, const void * pvItemToQueue )</tt>
*
* @see <https://www.freertos.org/xQueueOverwrite.html>
*
* Only for use with queues that have a length of one - so the queue is either
* empty or full.
*
* Post an item on a queue. If the queue is already full then overwrite the
* value held in the queue. The item is queued by copy, not by reference.
*
* This function must not be called from an interrupt service routine. See
* overwriteFromISR() for an alternative which may be used in an ISR.
*
* @param item A reference to the item that is to be placed on the queue.
*
* <b>Example Usage</b>
* @include Queue/overwrite.cpp
*/
inline void overwrite(const T& item) const { xQueueOverwrite(handle, &item); }
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueOverwriteFromISR(
* QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t
* *pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueOverwriteFromISR.html>
*
* A version of overwrite() that can be used in an interrupt service routine
* (ISR).
*
* Only for use with queues that can hold a single item - so the queue is
* either empty or full.
*
* Post an item on a queue. If the queue is already full then overwrite the
* value held in the queue. The item is queued by copy, not by reference.
*
* @param higherPriorityTaskWoken A reference that will be set to true if
* sending to the queue caused a task to unblock, and the unblocked task has a
* priority higher than the currently running task.
* @param item A reference to the item that is to be placed on the queue.
*
* <b>Example Usage</b>
* @include Queue/overwriteFromISR.cpp
*/
inline void overwriteFromISR(bool& higherPriorityTaskWoken,
const T& item) const {
BaseType_t taskWoken = pdFALSE;
xQueueOverwriteFromISR(handle, &item, &taskWoken);
if (taskWoken == pdTRUE) {
higherPriorityTaskWoken = true;
}
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueOverwriteFromISR(
* QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t
* *pxHigherPriorityTaskWoken )</tt>
*
* @see <https://www.freertos.org/xQueueOverwriteFromISR.html>
*
* @overload
*/
inline void overwriteFromISR(const T& item) const {
xQueueOverwriteFromISR(handle, &item, NULL);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueuePeek( QueueHandle_t xQueue,
* void * const pvBuffer, TickType_t xTicksToWait )</tt>
*
* @see <https://www.freertos.org/xQueuePeek.html>
*
* Receive an item from a queue without removing the item from the queue.
*
* Successfully received items remain on the queue so will be returned again
* by the next call, or a call to receive().
*
* This function must not be used in an interrupt service routine. See
* peekFromISR() for an alternative that can be called from an interrupt
* service routine.
*
* @param ticksToWait The maximum amount of time the task should block waiting
* for an item to receive should the queue be empty at the time of the call.
* Setting ticksToWait to 0 will cause the function to return immediately if
* the queue is empty. The time is defined in tick periods so the constant
* portTICK_PERIOD_MS should be used to convert to real time if this is
* required.
* @return std::optional<T> Object from the queue. User should check that the
* value is present.
*
* <b>Example Usage</b>
* @include Queue/peek.cpp
*/
inline std::optional<T> peek(
const TickType_t ticksToWait = portMAX_DELAY) const {
T buffer;
return (xQueuePeek(handle, &buffer, ticksToWait) == pdTRUE)
? std::optional<T>(buffer)
: std::nullopt;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueuePeekFromISR( QueueHandle_t
* xQueue, void *pvBuffer )</tt>
*
* @see <https://www.freertos.org/xQueuePeekFromISR.html>
*
* A version of peek() that can be called from an interrupt service routine
* (ISR).
*
* Receive an item from a queue without removing the item from the queue.
*
* Successfully received items remain on the queue so will be returned again
* by the next call, or a call to receive().
*
* @return std::optional<T> Object from the queue. User should check that the
* value is present.
*/
inline std::optional<T> peekFromISR() const {
T buffer;
return (xQueuePeekFromISR(handle, &buffer) == pdTRUE)
? std::optional<T>(buffer)
: std::nullopt;
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>void vQueueAddToRegistry( QueueHandle_t
* xQueue, char *pcQueueName )</tt>
*
* @see <https://www.freertos.org/vQueueAddToRegistry.html>
*
* The registry is provided as a means for kernel aware debuggers to locate
* queues, semaphores and mutexes. Call addToRegistry() add a queue,
* semaphore or mutex handle to the registry if you want the handle to be
* available to a kernel aware debugger. If you are not using a kernel aware
* debugger then this function can be ignored.
*
* configQUEUE_REGISTRY_SIZE defines the maximum number of handles the
* registry can hold. configQUEUE_REGISTRY_SIZE must be greater than 0 within
* FreeRTOSConfig.h for the registry to be available. Its value does not
* effect the number of queues, semaphores and mutexes that can be created -
* just the number that the registry can hold.
*
* If addToRegistry() is called more than once for the same queue, the
* registry will store the name parameter from the most recent call to
* addToRegistry().
*
* @param name The name to be associated with the handle. This is the name
* that the kernel aware debugger will display. The queue registry only
* stores a pointer to the string - so the string must be persistent (global
* or preferably in ROM/Flash), not on the stack.
*/
inline void addToRegistry(const char* name) const {
vQueueAddToRegistry(handle, name);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>void vQueueUnregisterQueue( QueueHandle_t
* xQueue )</tt>
*
* @see <https://www.freertos.org/vQueueUnregisterQueue.html>
*
* The registry is provided as a means for kernel aware debuggers to locate
* queues, semaphores and mutexes. Call addToRegistry() add a queue,
* semaphore or mutex handle to the registry if you want the handle to be
* available to a kernel aware debugger, and unregister() to remove the queue,
* semaphore or mutex from the register. If you are not using a kernel aware
* debugger then this function can be ignored.
*/
inline void unregister() const { vQueueUnregisterQueue(handle); }
/**
* Queue.hpp
*
* @brief Function that calls <tt>const char *pcQueueGetName( QueueHandle_t
* xQueue )</tt>
*
* @see <https://www.freertos.org/pcQueueGetName.html>
*
* The queue registry is provided as a means for kernel aware debuggers to
* locate queues, semaphores and mutexes. Call getName() to look up and return
* the name of a queue in the queue registry from the queue's handle.
*
* @return If the queue referenced by the queue is in the queue registry, then
* the text name of the queue is returned, otherwise NULL is returned.
*/
inline const char* getName() const { return pcQueueGetName(handle); }
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueIsQueueFullFromISR( const
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#xQueueIsQueueFullFromISR>
*
* Queries a queue to determine if the queue is empty. This function should
* only be used in an ISR.
*
* @return true if the queue is full.
* @return false if the queue is not full.
*/
inline bool isFullFromISR() const {
return (xQueueIsQueueFullFromISR(handle) == pdTRUE);
}
/**
* Queue.hpp
*
* @brief Function that calls <tt>BaseType_t xQueueIsQueueEmptyFromISR( const
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#xQueueIsQueueEmptyFromISR>
*
* Queries a queue to determine if the queue is empty. This function should
* only be used in an ISR.
*
* @retval true if the queue is empty.
* @retval false if the queue is not empty.
*/
inline bool isEmptyFromISR() const {
return (xQueueIsQueueEmptyFromISR(handle) == pdTRUE);
}
private:
/**
* Queue.hpp
*
* @brief Construct a new QueueBase object.
*
* @note Default constructor is deliberately private as this class is not
* intended to be instantiated or derived from by the user. Use
* FreeRTOS::Queue or FreeRTOS::StaticQueue.
*/
QueueBase() = default;
/**
* Queue.hpp
*
* @brief Destroy the QueueBase object by calling <tt>void vQueueDelete(
* QueueHandle_t xQueue )</tt>
*
* @see <https://www.freertos.org/a00018.html#vQueueDelete>
*
* Delete a queue - freeing all the memory allocated for storing of items
* placed on the queue.
*/
~QueueBase() { vQueueDelete(this->handle); }
QueueBase(QueueBase&&) noexcept = default;
QueueBase& operator=(QueueBase&&) noexcept = default;
/**
* @brief Handle used to refer to the queue when using the FreeRTOS interface.
*/
QueueHandle_t handle = NULL;
};
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
/**
* @class Queue Queue.hpp <FreeRTOS/Queue.hpp>
*
* @brief Class that encapsulates the functionality of a FreeRTOS queue.
*
* Each queue requires RAM that is used to hold the queue state, and to hold the
* items that are contained in the queue (the queue storage area). If a queue is
* created using this class then the required RAM is automatically allocated
* from the FreeRTOS heap.
*
* @tparam T Type to be stored in the queue.
*/
template <class T>
class Queue : public QueueBase<T> {
public:
/**
* Queue.hpp
*
* @brief Construct a new Queue object by calling <tt>QueueHandle_t
* xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize )</tt>
*
* @see <https://www.freertos.org/a00116.html>
*
* @warning The user should call isValid() on this object to verify that the
* queue was created successfully in case the memory required to create the
* queue could not be allocated.
*
* @param length The maximum number of items the queue can hold at any one
* time.
*
* <b>Example Usage</b>
* @include Queue/queue.cpp
*/
explicit Queue(const UBaseType_t length) {
this->handle = xQueueCreate(length, sizeof(T));
}
~Queue() = default;
Queue(const Queue&) = delete;
Queue& operator=(const Queue&) = delete;
Queue(Queue&&) noexcept = default;
Queue& operator=(Queue&&) noexcept = default;
};
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
#if (configSUPPORT_STATIC_ALLOCATION == 1)
/**
* @class StaticQueue Queue.hpp <FreeRTOS/Queue.hpp>
*
* @brief Class that encapsulates the functionality of a FreeRTOS queue.
*
* If a queue is created using this class then the RAM is provided by the
* application writer as part of the object instance and allows the RAM to be
* statically allocated at compile time.
*
* @tparam T Type to be stored in the queue.
* @tparam N The maximum number of items the queue can hold at any one time.
*/
template <class T, UBaseType_t N>
class StaticQueue : public QueueBase<T> {
public:
/**
* Queue.hpp
*
* @brief Construct a new StaticQueue object by calling
* <tt>QueueHandle_t xQueueCreateStatic( UBaseType_t uxQueueLength,
* UBaseType_t uxItemSize, uint8_t *pucQueueStorageBuffer, StaticQueue_t
* *pxQueueBuffer )</tt>
*
* @see <https://www.freertos.org/xQueueCreateStatic.html>
*
* @warning This class contains the storage buffer for the queue, so the user
* should create this object as a global object or with the static storage
* specifier so that the object instance is not on the stack.
*
* <b>Example Usage</b>
* @include Queue/staticQueue.cpp
*/
StaticQueue() {
this->handle = xQueueCreateStatic(N, sizeof(T), storage, &staticQueue);
}
~StaticQueue() = default;
StaticQueue(const StaticQueue&) = delete;
StaticQueue& operator=(const StaticQueue&) = delete;
StaticQueue(StaticQueue&&) noexcept = default;
StaticQueue& operator=(StaticQueue&&) noexcept = default;
private:
StaticQueue_t staticQueue;
uint8_t storage[N * sizeof(T)];
};
#endif /* configSUPPORT_STATIC_ALLOCATION */
} // namespace FreeRTOS
#endif // FREERTOS_QUEUE_HPP