src: add FreeRTOS c++ wrapper
This commit is contained in:
parent
9c4f85c033
commit
f331222b3c
503
source/test/src/FreeRTOSCPP/EventGroups.hpp
Normal file
503
source/test/src/FreeRTOSCPP/EventGroups.hpp
Normal file
@ -0,0 +1,503 @@
|
|||||||
|
/*
|
||||||
|
* 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_EVENTGROUPS_HPP
|
||||||
|
#define FREERTOS_EVENTGROUPS_HPP
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "event_groups.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class EventGroupBase EventGroupBase.hpp <FreeRTOS/EventGroups.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard event group interface to
|
||||||
|
* FreeRTOS::EventGroup and FreeRTOS::StaticEventGroup.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::EventGroup or FreeRTOS::StaticEventGroup.
|
||||||
|
*/
|
||||||
|
class EventGroupBase {
|
||||||
|
public:
|
||||||
|
friend class EventGroup;
|
||||||
|
friend class StaticEventGroup;
|
||||||
|
|
||||||
|
EventGroupBase(const EventGroupBase&) = delete;
|
||||||
|
EventGroupBase& operator=(const EventGroupBase&) = 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;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
using EventBits = std::bitset<((configUSE_16_BIT_TICKS == 1) ? 8 : 24)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks if the underlying event group handle is not
|
||||||
|
* NULL. This should be used to ensure an event group has been created
|
||||||
|
* correctly.
|
||||||
|
*
|
||||||
|
* @retval true the handle is not NULL.
|
||||||
|
* @retval false the handle is NULL.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupWaitBits( const
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const
|
||||||
|
* BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t
|
||||||
|
* xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupWaitBits.html>
|
||||||
|
*
|
||||||
|
* Read bits within an RTOS event group, optionally entering the Blocked state
|
||||||
|
* (with a timeout) to wait for a bit or group of bits to become set.
|
||||||
|
*
|
||||||
|
* @warning This function cannot be called from an interrupt.
|
||||||
|
*
|
||||||
|
* @param bitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||||
|
* inside the event group. bitsToWaitFor must not be set to 0.
|
||||||
|
* @param clearOnExit If clearOnExit is set to true then any bits set in the
|
||||||
|
* value passed as the bitsToWaitFor parameter will be cleared in the event
|
||||||
|
* group before wait() returns if wait() returns for any reason other than a
|
||||||
|
* timeout. The timeout value is set by the ticksToWait parameter. If
|
||||||
|
* clearOnExit is set to false then the bits set in the event group are not
|
||||||
|
* altered when the call to wait() returns.
|
||||||
|
* @param waitForAllBits waitForAllBits is used to create either a logical AND
|
||||||
|
* test (where all bits must be set) or a logical OR test (where one or more
|
||||||
|
* bits must be set) as follows: If waitForAllBits is set to true then wait()
|
||||||
|
* will return when either all the bits set in the value passed as the
|
||||||
|
* bitsToWaitFor parameter are set in the event group or the specified block
|
||||||
|
* time expires. If waitForAllBits is set to false then wait() will return
|
||||||
|
* when any of the bits set in the value passed as the bitsToWaitFor parameter
|
||||||
|
* are set in the event group or the specified block time expires.
|
||||||
|
* @param ticksToWait The maximum amount of time (specified in 'ticks') to
|
||||||
|
* wait for one/all (depending on the waitForAllBits value) of the bits
|
||||||
|
* specified by bitsToWaitFor to become set.
|
||||||
|
* @return EventBits The value of the event group at the time either the event
|
||||||
|
* bits being waited for became set, or the block time expired. The current
|
||||||
|
* value of the event bits in an event group will be different to the returned
|
||||||
|
* value if a higher priority task or interrupt changed the value of an event
|
||||||
|
* bit between the calling task leaving the Blocked state and exiting the
|
||||||
|
* wait() function. Test the return value to know which bits were set. If
|
||||||
|
* wait() returned because its timeout expired then not all the bits being
|
||||||
|
* waited for will be set. If wait() returned because the bits it was waiting
|
||||||
|
* for were set then the returned value is the event group value before any
|
||||||
|
* bits were automatically cleared because the clearOnExit parameter was set
|
||||||
|
* to true.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/wait.cpp
|
||||||
|
*/
|
||||||
|
inline EventBits wait(const EventBits& bitsToWaitFor = 0,
|
||||||
|
const bool clearOnExit = false,
|
||||||
|
const bool waitForAllBits = false,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return EventBits(xEventGroupWaitBits(
|
||||||
|
handle, bitsToWaitFor.to_ulong(), (clearOnExit ? pdTRUE : pdFALSE),
|
||||||
|
(waitForAllBits ? pdTRUE : pdFALSE), ticksToWait));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupSetBits(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupSetBits.html>
|
||||||
|
*
|
||||||
|
* Set bits (flags) within an RTOS event group. This function cannot be called
|
||||||
|
* from an interrupt. setFromISR() is a version that can be called from an
|
||||||
|
* interrupt.
|
||||||
|
*
|
||||||
|
* Setting bits in an event group will automatically unblock tasks that are
|
||||||
|
* blocked waiting for the bits.
|
||||||
|
*
|
||||||
|
* @param bitsToSet A bitwise value that indicates the bit or bits to set in
|
||||||
|
* the event group.
|
||||||
|
* @return EventBits The value of the event group at the time the call to
|
||||||
|
* set() returns. There are two reasons why the returned value might have the
|
||||||
|
* bits specified by the uxBitsToSet parameter cleared:
|
||||||
|
* 1. If setting a bit results in a task that was waiting for the bit leaving
|
||||||
|
* the blocked state then it is possible the bit will have been cleared
|
||||||
|
* automatically (see the clearOnExit parameter of wait()).
|
||||||
|
* 2. Any unblocked (or otherwise Ready state) task that has a priority above
|
||||||
|
* that of the task that called set() will execute and may change the event
|
||||||
|
* group value before the call to set() returns.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/set.cpp
|
||||||
|
*/
|
||||||
|
inline EventBits set(const EventBits& bitsToSet) const {
|
||||||
|
return EventBits(xEventGroupSetBits(handle, bitsToSet.to_ulong()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xEventGroupSetBitsFromISR(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t
|
||||||
|
* *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupSetBitsFromISR.html>
|
||||||
|
*
|
||||||
|
* Set bits (flags) within an RTOS event group. A version of set() that can be
|
||||||
|
* called from an interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* Setting bits in an event group will automatically unblock tasks that are
|
||||||
|
* blocked waiting for the bits.
|
||||||
|
*
|
||||||
|
* Setting bits in an event group is not a deterministic operation because
|
||||||
|
* there are an unknown number of tasks that may be waiting for the bit or
|
||||||
|
* bits being set. FreeRTOS does not allow non-deterministic operations to be
|
||||||
|
* performed in interrupts or from critical sections. Therefore
|
||||||
|
* xEventGroupSetBitFromISR() sends a message to the RTOS daemon task to have
|
||||||
|
* the set operation performed in the context of the daemon task - where a
|
||||||
|
* scheduler lock is used in place of a critical section.
|
||||||
|
*
|
||||||
|
* @note As mentioned in the paragraph above, setting bits from an ISR will
|
||||||
|
* defer the set operation to the RTOS daemon task (also known as the timer
|
||||||
|
* service task). The RTOS daemon task is scheduled according to its priority,
|
||||||
|
* just like any other RTOS task. Therefore, if it is essential the set
|
||||||
|
* operation completes immediately (before a task created by the application
|
||||||
|
* executes) then the priority of the RTOS daemon task must be higher than the
|
||||||
|
* priority of any application task that uses the event group. The priority of
|
||||||
|
* the RTOS daemon task is set by the configTIMER_TASK_PRIORITY definition in
|
||||||
|
* FreeRTOSConfig.h.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken As mentioned above, calling this function
|
||||||
|
* will result in a message being sent to the RTOS daemon task. If the
|
||||||
|
* priority of the daemon task is higher than the priority of the currently
|
||||||
|
* running task (the task the interrupt interrupted) then
|
||||||
|
* higherPriorityTaskWoken will be set to true by setFromISR(), indicating
|
||||||
|
* that a context switch should be requested before the interrupt exits. For
|
||||||
|
* that reason higherPriorityTaskWoken must be initialised to false. See the
|
||||||
|
* example code below.
|
||||||
|
* @param bitsToSet A bitwise value that indicates the bit or bits to set in
|
||||||
|
* the event group.
|
||||||
|
* @retval true If the message was sent to the RTOS daemon task.
|
||||||
|
* @retval false Otherwise or if the timer service queue was full
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/setFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool setFromISR(bool& higherPriorityTaskWoken,
|
||||||
|
const EventBits& bitsToSet) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xEventGroupSetBitsFromISR(handle, bitsToSet.to_ulong(),
|
||||||
|
&taskWoken) == pdPASS);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xEventGroupSetBitsFromISR(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t
|
||||||
|
* *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupSetBitsFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool setFromISR(const EventBits& bitsToSet) const {
|
||||||
|
return (xEventGroupSetBitsFromISR(handle, bitsToSet.to_ulong(), NULL) ==
|
||||||
|
pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupClearBits(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupClearBits.html>
|
||||||
|
*
|
||||||
|
* Clear bits (flags) within an RTOS event group. This function cannot be
|
||||||
|
* called from an interrupt. See clearFromISR() for a version that can be
|
||||||
|
* called from an interrupt.
|
||||||
|
*
|
||||||
|
* @param bitsToClear A bitwise value that indicates the bit or bits to clear
|
||||||
|
* in the event group.
|
||||||
|
* @return EventBits The value of the event group before the specified bits
|
||||||
|
* were cleared.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/clear.cpp
|
||||||
|
*/
|
||||||
|
inline EventBits clear(const EventBits& bitsToClear) const {
|
||||||
|
return EventBits(xEventGroupClearBits(handle, bitsToClear.to_ulong()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xEventGroupClearBitsFromISR(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupClearBitsFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of clear() that can be called from an interrupt. The clear
|
||||||
|
* operation is deferred to the RTOS daemon task which is also known as the
|
||||||
|
* timer service task. The priority of the daemon task is set by the
|
||||||
|
* configTIMER_TASK_PRIORITY setting in FreeRTOSConfig.h.
|
||||||
|
*
|
||||||
|
* @param bitsToClear A bitwise value that indicates the bit or bits to clear
|
||||||
|
* in the event group.
|
||||||
|
* @return true If the operation was successfully deferred to the RTOS daemon
|
||||||
|
* task.
|
||||||
|
* @return false If the timer command queue is full.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/clearFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool clearFromISR(const EventBits& bitsToClear) const {
|
||||||
|
return (xEventGroupClearBitsFromISR(handle, bitsToClear.to_ulong()) ==
|
||||||
|
pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupGetBits(
|
||||||
|
* EventGroupHandle_t xEventGroup )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupGetBits.html>
|
||||||
|
*
|
||||||
|
* Returns the current value of the event bits (event flags) in an RTOS event
|
||||||
|
* group. This function cannot be used from an interrupt. See getFromISR() for
|
||||||
|
* a version that can be used in an interrupt.
|
||||||
|
*
|
||||||
|
* @return EventBits The value of the event bits in the event group at the
|
||||||
|
* time get() was called.
|
||||||
|
*/
|
||||||
|
inline EventBits get() const { return EventBits(xEventGroupGetBits(handle)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupGetBitsFromISR(
|
||||||
|
* EventGroupHandle_t xEventGroup )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupGetBitsFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of get() that can be called from an interrupt.
|
||||||
|
*
|
||||||
|
* @return EventBits The value of the event bits in the event group at the
|
||||||
|
* time getFromISR() was called.
|
||||||
|
*/
|
||||||
|
inline EventBits getFromISR() const {
|
||||||
|
return EventBits(xEventGroupGetBitsFromISR(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>EventBits_t xEventGroupSync(
|
||||||
|
* EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const
|
||||||
|
* EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupSync.html>
|
||||||
|
*
|
||||||
|
* Atomically set bits (flags) within an RTOS event group, then wait for a
|
||||||
|
* combination of bits to be set within the same event group. This
|
||||||
|
* functionality is typically used to synchronize multiple tasks (often called
|
||||||
|
* a task rendezvous), where each task has to wait for the other tasks to
|
||||||
|
* reach a synchronization point before proceeding.
|
||||||
|
*
|
||||||
|
* This function cannot be used from an interrupt.
|
||||||
|
*
|
||||||
|
* The function will return before its block time expires if the bits
|
||||||
|
* specified by the bitsToWait parameter are set, or become set within that
|
||||||
|
* time. In this case all the bits specified by bitsToWait will be
|
||||||
|
* automatically cleared before the function returns.
|
||||||
|
*
|
||||||
|
* @param bitsToSet The bit or bits to set in the event group before
|
||||||
|
* determining if (and possibly waiting for), all the bits specified by the
|
||||||
|
* bitsToWait parameter are set.
|
||||||
|
* @param bitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||||
|
* inside the event group.
|
||||||
|
* @param ticksToWait The maximum amount of time (specified in 'ticks') to
|
||||||
|
* wait for all the bits specified by the uxBitsToWaitFor parameter value to
|
||||||
|
* become set.
|
||||||
|
* @return EventBits
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/sync.cpp
|
||||||
|
*/
|
||||||
|
inline EventBits sync(const EventBits& bitsToSet = 0,
|
||||||
|
const EventBits& bitsToWaitFor = 0,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return EventBits(xEventGroupSync(handle, bitsToSet.to_ulong(),
|
||||||
|
bitsToWaitFor.to_ulong(), ticksToWait));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new EventGroupBase object.
|
||||||
|
*
|
||||||
|
* @note Default constructor is deliberately private as this class is not
|
||||||
|
* intended to be instantiated or derived from by the user. Use
|
||||||
|
* FreeRTOS::EventGroup or FreeRTOS::StaticEventGroup.
|
||||||
|
*/
|
||||||
|
EventGroupBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventGroup.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the EventGroupBase object by calling <tt>void
|
||||||
|
* vEventGroupDelete( EventGroupHandle_t xEventGroup )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/vEventGroupDelete.html>
|
||||||
|
*
|
||||||
|
* Delete an event group.
|
||||||
|
*
|
||||||
|
* Tasks that are blocked on the event group being deleted will be unblocked,
|
||||||
|
* and report an event group value of 0.
|
||||||
|
*/
|
||||||
|
~EventGroupBase() { vEventGroupDelete(this->handle); };
|
||||||
|
|
||||||
|
EventGroupBase(EventGroupBase&&) noexcept = default;
|
||||||
|
EventGroupBase& operator=(EventGroupBase&&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle used to refer to the event group when using the FreeRTOS
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
EventGroupHandle_t handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class EventGroup EventGroups.hpp <FreeRTOS/EventGroups.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS event group.
|
||||||
|
*
|
||||||
|
* Each event group requires a [very] small amount of RAM that is used to hold
|
||||||
|
* the event group's state. If an event group is created using this class then
|
||||||
|
* the required RAM is automatically allocated from the FreeRTOS heap. If an
|
||||||
|
* event group is created using FreeRTOS::StaticEventGroup then the RAM is
|
||||||
|
* provided by the application writer, which requires an additional parameter,
|
||||||
|
* but allows the RAM to be statically allocated at compile time. See the Static
|
||||||
|
* Vs Dynamic allocation page for more information.
|
||||||
|
*/
|
||||||
|
class EventGroup : public EventGroupBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* EventGroup.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new EventGroup object by calling <tt>EventGroupHandle_t
|
||||||
|
* xEventGroupCreate( void )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupCreate.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.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include EventGroups/eventGroup.cpp
|
||||||
|
*/
|
||||||
|
EventGroup() { this->handle = xEventGroupCreate(); }
|
||||||
|
~EventGroup() = default;
|
||||||
|
|
||||||
|
EventGroup(const EventGroup&) = delete;
|
||||||
|
EventGroup& operator=(const EventGroup&) = delete;
|
||||||
|
|
||||||
|
EventGroup(EventGroup&&) noexcept = default;
|
||||||
|
EventGroup& operator=(EventGroup&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticEventGroup EventGroups.hpp <FreeRTOS/EventGroups.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS event group.
|
||||||
|
*
|
||||||
|
* Each event group requires a [very] small amount of RAM that is used to hold
|
||||||
|
* the event group's state. If an event group is created using
|
||||||
|
* FreeRTOS::EventGroup then the required RAM is automatically allocated from
|
||||||
|
* the FreeRTOS heap. If an event group is created using this class then the RAM
|
||||||
|
* is provided by the application writer, which requires an additional
|
||||||
|
* parameter, but allows the RAM to be statically allocated at compile time. See
|
||||||
|
* the Static Vs Dynamic allocation page for more information.
|
||||||
|
*/
|
||||||
|
class StaticEventGroup : public EventGroupBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* EventGroups.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticEventGroup object by calling
|
||||||
|
* <tt>EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t
|
||||||
|
* *pxEventGroupBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xEventGroupCreateStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the event group, 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 EventGroups/staticEventGroup.cpp
|
||||||
|
*/
|
||||||
|
StaticEventGroup() {
|
||||||
|
this->handle = xEventGroupCreateStatic(&staticEventGroup);
|
||||||
|
}
|
||||||
|
~StaticEventGroup() = default;
|
||||||
|
|
||||||
|
StaticEventGroup(const StaticEventGroup&) = delete;
|
||||||
|
StaticEventGroup& operator=(const StaticEventGroup&) = delete;
|
||||||
|
|
||||||
|
StaticEventGroup(StaticEventGroup&&) noexcept = default;
|
||||||
|
StaticEventGroup& operator=(StaticEventGroup&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticEventGroup_t staticEventGroup;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_EVENTGROUPS_HPP
|
||||||
409
source/test/src/FreeRTOSCPP/Kernel.hpp
Normal file
409
source/test/src/FreeRTOSCPP/Kernel.hpp
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
* 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_KERNEL_HPP
|
||||||
|
#define FREERTOS_KERNEL_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Kernel namespace that provides an interface to kernel functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace Kernel {
|
||||||
|
enum class SchedulerState : BaseType_t {
|
||||||
|
Suspended = taskSCHEDULER_SUSPENDED,
|
||||||
|
NotStarted = taskSCHEDULER_NOT_STARTED,
|
||||||
|
Running = taskSCHEDULER_RUNNING,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief If versionNumber ends with + it represents the version in development
|
||||||
|
* after the numbered release.
|
||||||
|
*/
|
||||||
|
inline constexpr char versionNumber[] = tskKERNEL_VERSION_NUMBER;
|
||||||
|
inline constexpr BaseType_t versionMajor = tskKERNEL_VERSION_MAJOR;
|
||||||
|
inline constexpr BaseType_t versionMinor = tskKERNEL_VERSION_MINOR;
|
||||||
|
inline constexpr BaseType_t versionBuild = tskKERNEL_VERSION_BUILD;
|
||||||
|
|
||||||
|
#if (INCLUDE_xTaskGetSchedulerState == 1)
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskGetSchedulerState()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00021.html#xTaskGetSchedulerState>
|
||||||
|
*
|
||||||
|
* @retval SchedulerState Returns the scheduler state as Running, NotStarted, or
|
||||||
|
* Suspended.
|
||||||
|
*/
|
||||||
|
inline SchedulerState getSchedulerState() {
|
||||||
|
return static_cast<SchedulerState>(xTaskGetSchedulerState());
|
||||||
|
}
|
||||||
|
#endif /* INCLUDE_xTaskGetSchedulerState */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>uxTaskGetNumberOfTasks()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00021.html#usTaskGetNumberOfTasks>
|
||||||
|
*
|
||||||
|
* @retval UBaseType_t The number of tasks that the real time kernel is
|
||||||
|
* currently managing. This includes all ready, blocked and suspended tasks. A
|
||||||
|
* task that has been deleted but not yet freed by the idle task will also be
|
||||||
|
* included in the count.
|
||||||
|
*/
|
||||||
|
inline UBaseType_t getNumberOfTasks() { return uxTaskGetNumberOfTasks(); }
|
||||||
|
|
||||||
|
#if (INCLUDE_xTaskGetIdleTaskHandle == 1 && configGENERATE_RUN_TIME_STATS == 1)
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskGetIdleRunTimeCounter()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00021.html#vTaskGetIdleRunTimeCounter>
|
||||||
|
*
|
||||||
|
* @retval TickType_t The run-time counter for the Idle task.
|
||||||
|
*
|
||||||
|
* This function can be used to determine how much CPU time the idle task
|
||||||
|
* receives. See the Run Time Stats page for a full description of the
|
||||||
|
* run-time-stats feature.
|
||||||
|
*
|
||||||
|
* configGENERATE_RUN_TIME_STATS and INCLUDE_xTaskGetIdleTaskHandle must both be
|
||||||
|
* defined as 1 for this function to be available. The application must also
|
||||||
|
* then provide definitions for portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() and
|
||||||
|
* portGET_RUN_TIME_COUNTER_VALUE to configure a peripheral timer/counter and
|
||||||
|
* return the timer's current count value respectively. It is recommended to
|
||||||
|
* make the timer at least 10 times the frequency of the tick count.
|
||||||
|
*/
|
||||||
|
inline TickType_t getIdleRunTimeCounter() {
|
||||||
|
return xTaskGetIdleRunTimeCounter();
|
||||||
|
}
|
||||||
|
#endif /* INCLUDE_xTaskGetIdleTaskHandle && configGENERATE_RUN_TIME_STATS*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskGetTickCount()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00021.html#xTaskGetTickCount>
|
||||||
|
*
|
||||||
|
* @retval TickType_t The count of ticks since
|
||||||
|
* FreeRTOS::Kernel::startScheduler() was called.
|
||||||
|
*/
|
||||||
|
inline TickType_t getTickCount() { return xTaskGetTickCount(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskGetTickCountFromISR()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00021.html#xTaskGetTickCountFromISR>
|
||||||
|
*
|
||||||
|
* @retval TickType_t The count of ticks since
|
||||||
|
* FreeRTOS::Kernel::startScheduler() was called.
|
||||||
|
*
|
||||||
|
* This is a version of FreeRTOS::Kernel::getTickCount() that is safe to be
|
||||||
|
* called from an ISR - provided that TickType_t is the natural word size of the
|
||||||
|
* microcontroller being used or interrupt nesting is either not supported or
|
||||||
|
* not being used.
|
||||||
|
*/
|
||||||
|
inline TickType_t getTickCountFromISR() { return xTaskGetTickCountFromISR(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskYIELD()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00020.html#taskYIELD>
|
||||||
|
*
|
||||||
|
* FreeRTOS::Kernel::yield() is used to request a context switch to another
|
||||||
|
*task. However, if there are no other tasks at a higher or equal priority to
|
||||||
|
*the task that calls FreeRTOS::Kernel::yield() then the RTOS scheduler will
|
||||||
|
*simply select the task that called FreeRTOS::Kernel::yield() to run again.
|
||||||
|
*/
|
||||||
|
inline void yield() { taskYIELD(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskENTER_CRITICAL()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/taskENTER_CRITICAL_taskEXIT_CRITICAL.html>
|
||||||
|
*
|
||||||
|
* Function to mark the start of a critical code region. Preemptive context
|
||||||
|
* switches cannot occur when in a critical region.
|
||||||
|
*
|
||||||
|
* @note This may alter the stack (depending on the portable implementation) so
|
||||||
|
* must be used with care!
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/enterExitCritical.cpp
|
||||||
|
*/
|
||||||
|
inline void enterCritical() { taskENTER_CRITICAL(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskENTER_CRITICAL_FROM_ISR()</tt>
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <https://www.freertos.org/taskENTER_CRITICAL_FROM_ISR_taskEXIT_CRITICAL_FROM_ISR.html>
|
||||||
|
*
|
||||||
|
* @retval uint32_t the interrupt mask state as it was before the macro was
|
||||||
|
* called. The value returned by FreeRTOS::Kernel::enterCriticalFromISR() must
|
||||||
|
* be used as the interruptStatus parameter in the matching call to
|
||||||
|
* FreeRTOS::Kernel::exitCriticalFromISR().
|
||||||
|
*
|
||||||
|
* Function to mark the start of a critical code region. Preemptive context
|
||||||
|
* switches cannot occur when in a critical region.
|
||||||
|
*
|
||||||
|
* @note This may alter the stack (depending on the portable implementation) so
|
||||||
|
* must be used with care!
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/enterExitCriticalFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline uint32_t enterCriticalFromISR() { return taskENTER_CRITICAL_FROM_ISR(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskEXIT_CRITICAL()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/taskENTER_CRITICAL_taskEXIT_CRITICAL.html>
|
||||||
|
*
|
||||||
|
* Function to mark the end of a critical code region. Preemptive context
|
||||||
|
* switches cannot occur when in a critical region.
|
||||||
|
*
|
||||||
|
* @note This may alter the stack (depending on the portable implementation) so
|
||||||
|
* must be used with care!
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/enterExitCritical.cpp
|
||||||
|
*/
|
||||||
|
inline void exitCritical() { taskEXIT_CRITICAL(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskEXIT_CRITICAL_FROM_ISR()</tt>
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <https://www.freertos.org/taskENTER_CRITICAL_FROM_ISR_taskEXIT_CRITICAL_FROM_ISR.html>
|
||||||
|
*
|
||||||
|
* @param interruptStatus The value used as the interruptStatus parameter must
|
||||||
|
* be the value returned from the matching call to
|
||||||
|
* FreeRTOS::Kernel::enterCriticalFromISR().
|
||||||
|
*
|
||||||
|
* Function to mark the end of a critical code region. Preemptive context
|
||||||
|
* switches cannot occur when in a critical region.
|
||||||
|
*
|
||||||
|
* @note This may alter the stack (depending on the portable implementation) so
|
||||||
|
* must be used with care!
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/enterExitCriticalFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline void exitCriticalFromISR(const uint32_t interruptStatus) {
|
||||||
|
taskEXIT_CRITICAL_FROM_ISR(interruptStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskDISABLE_INTERRUPTS()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00020.html#taskDISABLE_INTERRUPTS>
|
||||||
|
*
|
||||||
|
* Function to disable all maskable interrupts.
|
||||||
|
*/
|
||||||
|
inline void disableInterrupts() { taskDISABLE_INTERRUPTS(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>taskENABLE_INTERRUPTS()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00020.html#taskENABLE_INTERRUPTS>
|
||||||
|
*
|
||||||
|
* Function to enable microcontroller interrupts.
|
||||||
|
*/
|
||||||
|
inline void enableInterrupts() { taskENABLE_INTERRUPTS(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>vTaskStartScheduler()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00132.html>
|
||||||
|
*
|
||||||
|
* Starts the real time kernel tick processing. After calling the kernel has
|
||||||
|
* control over which tasks are executed and when.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/startScheduler.cpp
|
||||||
|
*/
|
||||||
|
inline void startScheduler() { vTaskStartScheduler(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>vTaskEndScheduler()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00133.html>
|
||||||
|
*
|
||||||
|
* @note At the time of writing only the x86 real mode port, which runs on a PC
|
||||||
|
* in place of DOS, implements this function.
|
||||||
|
*
|
||||||
|
* Stops the real time kernel tick. All created tasks will be automatically
|
||||||
|
* deleted and multitasking (either preemptive or cooperative) will stop.
|
||||||
|
* Execution then resumes from the point where
|
||||||
|
* FreeRTOS::Kernel::startScheduler() was called, as if
|
||||||
|
* FreeRTOS::Kernel::startScheduler() had just returned.
|
||||||
|
*
|
||||||
|
* See the demo application file main. c in the demo/PC directory for an example
|
||||||
|
* that uses FreeRTOS::Kernel::endScheduler().
|
||||||
|
*
|
||||||
|
* FreeRTOS::Kernel::endScheduler() requires an exit function to be defined
|
||||||
|
* within the portable layer (see vPortEndScheduler () in port. c for the PC
|
||||||
|
* port). This performs hardware specific operations such as stopping the
|
||||||
|
* kernel tick.
|
||||||
|
*
|
||||||
|
* FreeRTOS::Kernel::endScheduler() will cause all of the resources allocated by
|
||||||
|
* the kernel to be freed - but will not free resources allocated by application
|
||||||
|
* tasks.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/endScheduler.cpp
|
||||||
|
*/
|
||||||
|
inline void endScheduler() { vTaskEndScheduler(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>vTaskSuspendAll()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00134.html>
|
||||||
|
*
|
||||||
|
* Suspends the scheduler without disabling interrupts. Context switches will
|
||||||
|
* not occur while the scheduler is suspended.
|
||||||
|
*
|
||||||
|
* After calling FreeRTOS::Kernel::suspendAll() the calling task will continue
|
||||||
|
* to execute without risk of being swapped out until a call to
|
||||||
|
* FreeRTOS::Kernel::resumeAll() has been made.
|
||||||
|
*
|
||||||
|
* API functions that have the potential to cause a context switch (for example,
|
||||||
|
* FreeRTOS::Task::delayUntil(), FreeRTOS::Queue::send(), etc.) must not be
|
||||||
|
* called while the scheduler is suspended.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/suspendAll.cpp
|
||||||
|
*/
|
||||||
|
inline void suspendAll() { vTaskSuspendAll(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskResumeAll()</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00135.html>
|
||||||
|
*
|
||||||
|
* Resumes scheduler activity after it was suspended by a call to
|
||||||
|
* FreeRTOS::Kernel::suspendAll().
|
||||||
|
*
|
||||||
|
* FreeRTOS::Kernel::resumeAll() only resumes the scheduler. It does not
|
||||||
|
* unsuspend tasks that were previously suspended by a call to
|
||||||
|
* FreeRTOS::Task::suspend().
|
||||||
|
*
|
||||||
|
* @retval true If resuming the scheduler caused a context switch.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Kernel/resumeAll.cpp
|
||||||
|
*/
|
||||||
|
inline bool resumeAll() { return (xTaskResumeAll() == pdTRUE); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>vTaskStepTick( const TickType_t xTicksToJump
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/vTaskStepTick.html>
|
||||||
|
*
|
||||||
|
* Only available when configUSE_TICKLESS_IDLE is set to 1. If tickless mode is
|
||||||
|
* being used, or a low power mode is implemented, then the tick interrupt will
|
||||||
|
* not execute during idle periods. When this is the case, the tick count value
|
||||||
|
* maintained by the scheduler needs to be kept up to date with the actual
|
||||||
|
* execution time by being skipped forward by a time equal to the idle period.
|
||||||
|
*
|
||||||
|
* @param ticksToJump The number of RTOS ticks that have passed since the tick
|
||||||
|
* interrupt was stopped.
|
||||||
|
*/
|
||||||
|
inline void stepTick(const TickType_t ticksToJump) {
|
||||||
|
vTaskStepTick(ticksToJump);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kernel.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xTaskCatchUpTicks( TickType_t xTicksToCatchUp
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/vTaskStepTick.html>
|
||||||
|
*
|
||||||
|
* This function corrects the tick count value after the application code has
|
||||||
|
* held interrupts disabled for an extended period resulting in tick interrupts
|
||||||
|
* having been missed.
|
||||||
|
*
|
||||||
|
* This function is similar to FreeRTOS::Kernel::stepTick(), however, unlike
|
||||||
|
* FreeRTOS::Kernel::stepTick(), FreeRTOS::Kernel::catchUpTicks() may move the
|
||||||
|
* tick count forward past a time at which a task should be removed from the
|
||||||
|
* blocked state. That means tasks may have to be removed from the blocked
|
||||||
|
* state as the tick count is moved.
|
||||||
|
*
|
||||||
|
* @param ticksToCatchUp The number of tick interrupts that have been missed due
|
||||||
|
* to interrupts being disabled. Its value is not computed automatically, so
|
||||||
|
* must be computed by the application writer.
|
||||||
|
*
|
||||||
|
* @retval true If moving the tick count forward resulted in a task leaving the
|
||||||
|
* blocked state and a context switch being performed.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool catchUpTicks(const TickType_t ticksToCatchUp) {
|
||||||
|
return (xTaskCatchUpTicks(ticksToCatchUp) == pdTRUE);
|
||||||
|
}
|
||||||
|
} // namespace Kernel
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_KERNEL_HPP
|
||||||
518
source/test/src/FreeRTOSCPP/MessageBuffer.hpp
Normal file
518
source/test/src/FreeRTOSCPP/MessageBuffer.hpp
Normal file
@ -0,0 +1,518 @@
|
|||||||
|
/*
|
||||||
|
* 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_MESSAGEBUFFER_HPP
|
||||||
|
#define FREERTOS_MESSAGEBUFFER_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "message_buffer.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class MessageBufferBase MessageBuffer.hpp <FreeRTOS/MessageBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard message buffer interface to
|
||||||
|
* FreeRTOS::MessageBuffer and FreeRTOS::StaticMessageBuffer.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::MessageBuffer or FreeRTOS::StaticMessageBuffer.
|
||||||
|
*
|
||||||
|
* @warning Uniquely among FreeRTOS objects, the stream buffer implementation
|
||||||
|
* (so also the message buffer implementation, as message buffers are built on
|
||||||
|
* top of stream buffers) assumes there is only one task or interrupt that will
|
||||||
|
* write to the buffer (the writer), and only one task or interrupt that will
|
||||||
|
* read from the buffer (the reader). It is safe for the writer and reader to
|
||||||
|
* be different tasks or interrupts, but, unlike other FreeRTOS objects, it is
|
||||||
|
* not safe to have multiple different writers or multiple different readers. If
|
||||||
|
* there are to be multiple different writers then the application writer must
|
||||||
|
* place each call to a writing API function (such as send()) inside a critical
|
||||||
|
* section and set the send block time to 0. Likewise, if there are to be
|
||||||
|
* multiple different readers then the application writer must place each call
|
||||||
|
* to a reading API function (such as read()) inside a critical section and set
|
||||||
|
* the receive block time to 0.
|
||||||
|
*/
|
||||||
|
class MessageBufferBase {
|
||||||
|
public:
|
||||||
|
friend class MessageBuffer;
|
||||||
|
template <size_t>
|
||||||
|
friend class StaticMessageBuffer;
|
||||||
|
|
||||||
|
MessageBufferBase(const MessageBufferBase&) = delete;
|
||||||
|
MessageBufferBase& operator=(const MessageBufferBase&) = 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks if the underlying message buffer handle is not
|
||||||
|
* NULL. This should be used to ensure a message buffer has been created
|
||||||
|
* correctly.
|
||||||
|
*
|
||||||
|
* @retval true If the handle is not NULL.
|
||||||
|
* @retval false If the handle is NULL.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferSend(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferSend.html>
|
||||||
|
*
|
||||||
|
* Sends a discrete message to the message buffer. The message can be any
|
||||||
|
* length that fits within the buffer's free space, and is copied into the
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* Use send() to write to a message buffer from a task. Use sendFromISR() to
|
||||||
|
* write to a message buffer from an interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param data A pointer to the message that is to be copied into the message
|
||||||
|
* buffer.
|
||||||
|
* @param length The length of the message. That is, the number of bytes to
|
||||||
|
* copy from data into the message buffer. When a message is written to the
|
||||||
|
* message buffer an additional sizeof( size_t ) bytes are also written to
|
||||||
|
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||||
|
* 32-bit architecture, so on most 32-bit architecture setting length to 20
|
||||||
|
* will reduce the free space in the message buffer by 24 bytes (20 bytes of
|
||||||
|
* message data and 4 bytes to hold the message length).
|
||||||
|
* @param ticksToWait The maximum amount of time the calling task should
|
||||||
|
* remain in the Blocked state to wait for enough space to become available in
|
||||||
|
* the message buffer, should the message buffer have insufficient space when
|
||||||
|
* send() is called. The calling task will never block if ticksToWait is
|
||||||
|
* zero. The block time is specified in tick periods, so the absolute time it
|
||||||
|
* represents is dependent on the tick frequency. The macro pdMS_TO_TICKS()
|
||||||
|
* can be used to convert a time specified in milliseconds into a time
|
||||||
|
* specified in ticks. Setting ticksToWait to portMAX_DELAY will cause the
|
||||||
|
* task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||||
|
* CPU time when they are in the Blocked state.
|
||||||
|
* @return size_t The number of bytes written to the message buffer. If the
|
||||||
|
* call to send() times out before there was enough space to write the message
|
||||||
|
* into the message buffer then zero is returned. If the call did not time
|
||||||
|
* out then length is returned.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include MessageBuffer/send.cpp
|
||||||
|
*/
|
||||||
|
inline size_t send(const void* data, const size_t length,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return xMessageBufferSend(handle, data, length, ticksToWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferSendFromISR(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferSendFromISR.html>
|
||||||
|
*
|
||||||
|
* Interrupt safe version of the API function that sends a discrete message to
|
||||||
|
* the message buffer. The message can be any length that fits within the
|
||||||
|
* buffer's free space, and is copied into the buffer.
|
||||||
|
*
|
||||||
|
* Use send() to write to a message buffer from a task. Use sendFromISR() to
|
||||||
|
* write to a message buffer from an interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible that a message buffer will
|
||||||
|
* have a task blocked on it waiting for data. Calling sendFromISR() can make
|
||||||
|
* data available, and so cause a task that was waiting for data to leave the
|
||||||
|
* Blocked state. If calling sendFromISR() causes a task to leave the Blocked
|
||||||
|
* state, and the unblocked task has a priority higher than the currently
|
||||||
|
* executing task (the task that was interrupted), then, internally,
|
||||||
|
* sendFromISR() will set higherPriorityTaskWoken to true. If sendFromISR()
|
||||||
|
* sets this value to true, then normally a context switch should be performed
|
||||||
|
* before the interrupt is exited. This will ensure that the interrupt returns
|
||||||
|
* directly to the highest priority Ready state task. higherPriorityTaskWoken
|
||||||
|
* should be set to false before it is passed into the function. See the code
|
||||||
|
* example below for an example.
|
||||||
|
* @param data A pointer to the message that is to be copied into the message
|
||||||
|
* buffer.
|
||||||
|
* @param length The length of the message. That is, the number of bytes to
|
||||||
|
* copy from data into the message buffer. When a message is written to the
|
||||||
|
* message buffer an additional sizeof( size_t ) bytes are also written to
|
||||||
|
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||||
|
* 32-bit architecture, so on most 32-bit architecture setting length to 20
|
||||||
|
* will reduce the free space in the message buffer by 24 bytes (20 bytes of
|
||||||
|
* message data and 4 bytes to hold the message length).
|
||||||
|
* @return size_t The number of bytes actually written to the message buffer.
|
||||||
|
* If the message buffer didn't have enough free space for the message to be
|
||||||
|
* stored then 0 is returned, otherwise length is returned.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include MessageBuffer/sendFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline size_t sendFromISR(bool& higherPriorityTaskWoken, const void* data,
|
||||||
|
const size_t length) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
size_t result = xMessageBufferSendFromISR(handle, data, length, &taskWoken);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferSendFromISR(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferSendFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline size_t sendFromISR(const void* data, const size_t length) const {
|
||||||
|
return xMessageBufferSendFromISR(handle, data, length, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferReceive(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferReceive.html>
|
||||||
|
*
|
||||||
|
* Use receive() to read from a message buffer from a task.
|
||||||
|
* UsereceiveFromISR() to read from a message buffer from an interrupt service
|
||||||
|
* routine (ISR).
|
||||||
|
*
|
||||||
|
* @param buffer A pointer to the buffer into which the received message is to
|
||||||
|
* be copied.
|
||||||
|
* @param bufferLength The length of the buffer pointed to by the buffer
|
||||||
|
* parameter. This sets the maximum length of the message that can be
|
||||||
|
* received. If bufferLength is too small to hold the next message then the
|
||||||
|
* message will be left in the message buffer and 0 will be returned.
|
||||||
|
* @param ticksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for a message, should the message buffer be empty.
|
||||||
|
* receive() will return immediately if ticksToWait is zero and the message
|
||||||
|
* buffer is empty. The block time is specified in tick periods, so the
|
||||||
|
* absolute time it represents is dependent on the tick frequency. The macro
|
||||||
|
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||||
|
* into a time specified in ticks. Setting ticksToWait to portMAX_DELAY will
|
||||||
|
* cause the task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||||
|
* CPU time when they are in the Blocked state.
|
||||||
|
* @return size_t The length, in bytes, of the message read from the message
|
||||||
|
* buffer, if any. If receive() times out before a message became available
|
||||||
|
* then zero is returned. If the length of the message is greater than
|
||||||
|
* bufferLength then the message will be left in the message buffer and zero
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include MessageBuffer/receive.cpp
|
||||||
|
*/
|
||||||
|
inline size_t receive(void* buffer, const size_t bufferLength,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return xMessageBufferReceive(handle, buffer, bufferLength, ticksToWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferReceiveFromISR(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferReceiveFromISR.html>
|
||||||
|
*
|
||||||
|
* Use receive() to read from a message buffer from a task.
|
||||||
|
* UsereceiveFromISR() to read from a message buffer from an interrupt service
|
||||||
|
* routine (ISR).
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible that a message buffer will
|
||||||
|
* have a task blocked on it waiting for space to become available. Calling
|
||||||
|
* receiveFromISR() can make space available, and so cause a task that is
|
||||||
|
* waiting for space to leave the Blocked state. If calling receiveFromISR()
|
||||||
|
* causes a task to leave the Blocked state, and the unblocked task has a
|
||||||
|
* priority higher than the currently executing task (the task that was
|
||||||
|
* interrupted), then, internally, receiveFromISR() will set
|
||||||
|
* higherPriorityTaskWoken to true. If receiveFromISR() sets this value to
|
||||||
|
* true, then normally a context switch should be performed before the
|
||||||
|
* interrupt is exited. That will ensure the interrupt returns directly to the
|
||||||
|
* highest priority Ready state task. higherPriorityTaskWoken should be set
|
||||||
|
* to false before it is passed into the function. See the code example below
|
||||||
|
* for an example.
|
||||||
|
* @param buffer A pointer to the buffer into which the received message is to
|
||||||
|
* be copied.
|
||||||
|
* @param bufferLength The length of the buffer pointed to by the buffer
|
||||||
|
* parameter. This sets the maximum length of the message that can be
|
||||||
|
* received. If bufferLength is too small to hold the next message then the
|
||||||
|
* message will be left in the message buffer and 0 will be returned.
|
||||||
|
* @return size_t The length, in bytes, of the message read from the message
|
||||||
|
* buffer, if any.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include MessageBuffer/receiveFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline size_t receiveFromISR(bool& higherPriorityTaskWoken, void* buffer,
|
||||||
|
const size_t bufferLength) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
size_t result =
|
||||||
|
xMessageBufferReceiveFromISR(handle, buffer, bufferLength, &taskWoken);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferReceiveFromISR(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferReceiveFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline size_t receiveFromISR(void* buffer, const size_t bufferLength) const {
|
||||||
|
return xMessageBufferReceiveFromISR(handle, buffer, bufferLength, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xMessageBufferSpacesAvailable(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferSpacesAvailable.html>
|
||||||
|
*
|
||||||
|
* Queries a message buffer to see how much free space it contains, which is
|
||||||
|
* equal to the amount of data that can be sent to the message buffer before
|
||||||
|
* it is full. The returned value is 4 bytes larger than the maximum message
|
||||||
|
* size that can be sent to the message buffer.
|
||||||
|
*
|
||||||
|
* @return size_t The number of bytes that can be written to the message
|
||||||
|
* buffer before the message buffer would be full. When a message is written
|
||||||
|
* to the message buffer an additional sizeof( size_t ) bytes are also written
|
||||||
|
* to store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||||
|
* 32-bit architecture, so if spacesAvailable() returns 10, then the size of
|
||||||
|
* the largest message that can be written to the message buffer is 6 bytes.
|
||||||
|
*/
|
||||||
|
inline size_t spacesAvailable() const {
|
||||||
|
return xMessageBufferSpacesAvailable(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xMessageBufferReset(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferReset.html>
|
||||||
|
*
|
||||||
|
* Resets a message buffer to its initial, empty, state. Any data that was in
|
||||||
|
* the message buffer is discarded. A message buffer can only be reset if
|
||||||
|
* there are no tasks blocked waiting to either send to or receive from the
|
||||||
|
* message buffer.
|
||||||
|
*
|
||||||
|
* @retval true If the message buffer is reset.
|
||||||
|
* @retval false If there was a task blocked waiting to send to or read from
|
||||||
|
* the message buffer then the message buffer will not be reset.
|
||||||
|
*/
|
||||||
|
inline bool reset() const { return (xMessageBufferReset(handle) == pdPASS); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xMessageBufferIsEmpty(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferIsEmpty.html>
|
||||||
|
*
|
||||||
|
* Queries a message buffer to see if it is empty. A message buffer is empty
|
||||||
|
* if it does not contain any messages.
|
||||||
|
*
|
||||||
|
* @retval true If the message buffer is empty.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool isEmpty() const {
|
||||||
|
return (xMessageBufferIsEmpty(handle) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xMessageBufferIsFull(
|
||||||
|
* MessageBufferHandle_t xMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferIsFull.html>
|
||||||
|
*
|
||||||
|
* Queries a message buffer to see if it is full. A message buffer is full if
|
||||||
|
* it cannot accept any more messages, of any size, until space is made
|
||||||
|
* available by a message being removed from the message buffer.
|
||||||
|
*
|
||||||
|
* @retval true If the message buffer is full.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool isFull() const {
|
||||||
|
return (xMessageBufferIsFull(handle) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MessageBufferBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the MessageBufferBase object by calling <tt>void
|
||||||
|
* vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/vMessageBufferDelete.html>
|
||||||
|
*
|
||||||
|
* Delete a queue - freeing all the memory allocated for storing of items
|
||||||
|
* placed on the queue.
|
||||||
|
*/
|
||||||
|
~MessageBufferBase() { vMessageBufferDelete(this->handle); }
|
||||||
|
|
||||||
|
MessageBufferBase(MessageBufferBase&&) noexcept = default;
|
||||||
|
MessageBufferBase& operator=(MessageBufferBase&&) noexcept = default;
|
||||||
|
|
||||||
|
MessageBufferHandle_t handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class MessageBuffer MessageBuffer.hpp <FreeRTOS/MessageBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS message
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* A message buffer using dynamically allocated memory from the FreeRTOS heap.
|
||||||
|
* See FreeRTOS::StaticMessageBuffer for a version that uses statically
|
||||||
|
* allocated memory (memory that is allocated at compile time).
|
||||||
|
*/
|
||||||
|
class MessageBuffer : public MessageBufferBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new MessageBuffer object by calling
|
||||||
|
* <tt>MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferCreate.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* message buffer was created successfully in case the memory required to
|
||||||
|
* create the message buffer could not be allocated.
|
||||||
|
*
|
||||||
|
* @param size The total number of bytes (not messages) the message buffer
|
||||||
|
* will be able to hold at any one time. When a message is written to the
|
||||||
|
* message buffer an additional sizeof( size_t ) bytes are also written to
|
||||||
|
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||||
|
* 32-bit architecture, so on most 32-bit architectures a 10 byte message will
|
||||||
|
* take up 14 bytes of message buffer space.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include MessageBuffer/messageBuffer.cpp
|
||||||
|
*/
|
||||||
|
explicit MessageBuffer(size_t size) {
|
||||||
|
this->handle = xMessageBufferCreate(size);
|
||||||
|
}
|
||||||
|
~MessageBuffer() = default;
|
||||||
|
|
||||||
|
MessageBuffer(const MessageBuffer&) = delete;
|
||||||
|
MessageBuffer& operator=(const MessageBuffer&) = delete;
|
||||||
|
|
||||||
|
MessageBuffer(MessageBuffer&&) noexcept = default;
|
||||||
|
MessageBuffer& operator=(MessageBuffer&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticMessageBuffer MessageBuffer.hpp <FreeRTOS/MessageBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS message
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* If a message buffer 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 N The size, in bytes, of the storage for the message buffer.
|
||||||
|
*/
|
||||||
|
template <size_t N>
|
||||||
|
class StaticMessageBuffer : public MessageBufferBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* MessageBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticMessageBuffer object by calling
|
||||||
|
* <tt>MessageBufferHandle_t xMessageBufferCreateStatic( size_t
|
||||||
|
* xBufferSizeBytes, uint8_t *pucMessageBufferStorageArea,
|
||||||
|
* StaticMessageBuffer_t *pxStaticMessageBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xMessageBufferCreateStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the message buffer, 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 MessageBuffer/staticMessageBuffer.cpp
|
||||||
|
*/
|
||||||
|
StaticMessageBuffer() : MessageBufferBase() {
|
||||||
|
this->handle = xMessageBufferCreateStatic(sizeof(storage), storage,
|
||||||
|
&staticMessageBuffer);
|
||||||
|
}
|
||||||
|
~StaticMessageBuffer() = default;
|
||||||
|
|
||||||
|
StaticMessageBuffer(const StaticMessageBuffer&) = delete;
|
||||||
|
StaticMessageBuffer& operator=(const StaticMessageBuffer&) = delete;
|
||||||
|
|
||||||
|
StaticMessageBuffer(StaticMessageBuffer&&) noexcept = default;
|
||||||
|
StaticMessageBuffer& operator=(StaticMessageBuffer&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticMessageBuffer_t staticMessageBuffer;
|
||||||
|
uint8_t storage[N] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_MESSAGEBUFFER_HPP
|
||||||
495
source/test/src/FreeRTOSCPP/Mutex.hpp
Normal file
495
source/test/src/FreeRTOSCPP/Mutex.hpp
Normal file
@ -0,0 +1,495 @@
|
|||||||
|
/*
|
||||||
|
* 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_MUTEX_HPP
|
||||||
|
#define FREERTOS_MUTEX_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class MutexBase Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard mutex interface to
|
||||||
|
* FreeRTOS::Mutex, FreeRTOS::StaticMutex, FreeRTOS::RecursiveMutex, and
|
||||||
|
* FreeRTOS::StaticRecursiveMutex.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::Mutex, FreeRTOS::StaticMutex, FreeRTOS::RecursiveMutex, and
|
||||||
|
* FreeRTOS::StaticRecursiveMutex.
|
||||||
|
*/
|
||||||
|
class MutexBase {
|
||||||
|
public:
|
||||||
|
friend class Mutex;
|
||||||
|
friend class StaticMutex;
|
||||||
|
friend class RecursiveMutexBase;
|
||||||
|
friend class RecursiveMutex;
|
||||||
|
friend class StaticRecursiveMutex;
|
||||||
|
|
||||||
|
MutexBase(const MutexBase&) = delete;
|
||||||
|
MutexBase& operator=(const MutexBase&) = 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks if the underlying semaphore handle is not NULL.
|
||||||
|
* This should be used to ensure a semaphore has been created correctly.
|
||||||
|
*
|
||||||
|
* @retval true the handle is not NULL.
|
||||||
|
* @retval false the handle is NULL.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTake( SemaphoreHandle_t
|
||||||
|
* xSemaphore, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00122.html>
|
||||||
|
*
|
||||||
|
* @param ticksToWait The time in ticks to wait for the mutex to become
|
||||||
|
* available. The macro portTICK_PERIOD_MS can be used to convert this to a
|
||||||
|
* real time. A block time of zero can be used to poll the mutex.
|
||||||
|
* @retval true If the mutex was locked.
|
||||||
|
* @retval false If ticksToWait expired without the mutex becoming available.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/lock.cpp
|
||||||
|
*/
|
||||||
|
inline bool lock(const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return (xSemaphoreTake(handle, ticksToWait) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTakeFromISR ( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreTakeFromISR.html>
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible (although unlikely, and
|
||||||
|
* dependent on the semaphore type) that a mutex will have one or more tasks
|
||||||
|
* blocked on it waiting to give the mutex. Calling lockFromISR() will make a
|
||||||
|
* task that was blocked waiting to give the mutex leave the Blocked state. If
|
||||||
|
* calling the API function causes a task to leave the Blocked state, and the
|
||||||
|
* unblocked task has a priority equal to or higher than the currently
|
||||||
|
* executing task (the task that was interrupted), then, internally, the API
|
||||||
|
* function will set higherPriorityTaskWoken to true.
|
||||||
|
* @return true If the mutex was successfully locked.
|
||||||
|
* @return false If the mutex was not successfully locked because it was not
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
inline bool lockFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xSemaphoreTakeFromISR(handle, &taskWoken) == pdTRUE);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTakeFromISR ( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreTakeFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool lockFromISR() const {
|
||||||
|
return (xSemaphoreTakeFromISR(handle, NULL) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreGive( SemaphoreHandle_t xSemaphore
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00123.html>
|
||||||
|
*
|
||||||
|
* @warning This must not be used from an ISR.
|
||||||
|
*
|
||||||
|
* @return true If the mutex was unlocked.
|
||||||
|
* @return false If an error occurred. Mutexes (semaphores) are implemented
|
||||||
|
* using queues. An error can occur if there is no space on the queue to post
|
||||||
|
* a message indicating that the mutex was not first locked correctly.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/unlock.cpp
|
||||||
|
*/
|
||||||
|
inline bool unlock() const { return (xSemaphoreGive(handle) == pdTRUE); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MutexBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the MutexBase object by calling <tt>void vSemaphoreDelete(
|
||||||
|
* SemaphoreHandle_t xSemaphore )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00113.html#vSemaphoreDelete>
|
||||||
|
*
|
||||||
|
* @note Do not delete a mutex that has tasks blocked on it (tasks that are in
|
||||||
|
* the Blocked state waiting for the mutex to become available).
|
||||||
|
*/
|
||||||
|
~MutexBase() { vSemaphoreDelete(this->handle); }
|
||||||
|
|
||||||
|
MutexBase(MutexBase&&) noexcept = default;
|
||||||
|
MutexBase& operator=(MutexBase&&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle used to refer to the semaphore when using the FreeRTOS
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
SemaphoreHandle_t handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class RecursiveMutexBase Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the recursive mutex interface to
|
||||||
|
* FreeRTOS::RecursiveMutex and FreeRTOS::StaticRecursiveMutex. This class
|
||||||
|
* exists to override the lock() and unlock() functions which require different
|
||||||
|
* underlying functions from what is used in FreeRTOS::MutexBase.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::RecursiveMutex or FreeRTOS::StaticRecursiveMutex.
|
||||||
|
*/
|
||||||
|
class RecursiveMutexBase : public MutexBase {
|
||||||
|
public:
|
||||||
|
friend class RecursiveMutex;
|
||||||
|
friend class StaticRecursiveMutex;
|
||||||
|
|
||||||
|
RecursiveMutexBase(const RecursiveMutexBase&) = delete;
|
||||||
|
RecursiveMutexBase& operator=(const RecursiveMutexBase&) = delete;
|
||||||
|
|
||||||
|
static void* operator new(size_t, void*);
|
||||||
|
static void* operator new[](size_t, void*);
|
||||||
|
static void* operator new(size_t) = delete;
|
||||||
|
static void* operator new[](size_t) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTakeRecursive( SemaphoreHandle_t
|
||||||
|
* xMutex, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreTakeRecursive.html>
|
||||||
|
*
|
||||||
|
* @param ticksToWait The time in ticks to wait for the mutex to become
|
||||||
|
* available. The macro portTICK_PERIOD_MS can be used to convert this to a
|
||||||
|
* real time. A block time of zero can be used to poll the mutex. If the task
|
||||||
|
* already owns the mutex then take() will return immediately no matter what
|
||||||
|
* the value of ticksToWait.
|
||||||
|
* @retval true If the mutex was locked.
|
||||||
|
* @retval false If ticksToWait expired without the mutex becoming available.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/recursiveLock.cpp
|
||||||
|
*/
|
||||||
|
inline bool lock(const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return (xSemaphoreTakeRecursive(handle, ticksToWait) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreGiveRecursive( SemaphoreHandle_t
|
||||||
|
* xSemaphore )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreGiveRecursive.html>
|
||||||
|
*
|
||||||
|
* A mutex used recursively can be locked repeatedly by the owner. The mutex
|
||||||
|
* doesn't become available again until the owner has called unlock() for each
|
||||||
|
* successful lock request. For example, if a task successfully locks the
|
||||||
|
* same mutex 5 times then the mutex will not be available to any other task
|
||||||
|
* until it has also unlocked the mutex back exactly five times.
|
||||||
|
*
|
||||||
|
* @return true If the mutex was unlocked.
|
||||||
|
* @return false Otherwise.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/recursiveLock.cpp
|
||||||
|
*/
|
||||||
|
inline bool unlock() const {
|
||||||
|
return (xSemaphoreGiveRecursive(handle) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RecursiveMutexBase() = default;
|
||||||
|
~RecursiveMutexBase() = default;
|
||||||
|
|
||||||
|
RecursiveMutexBase(RecursiveMutexBase&&) noexcept = default;
|
||||||
|
RecursiveMutexBase& operator=(RecursiveMutexBase&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Mutex Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS mutex.
|
||||||
|
*
|
||||||
|
* Each mutex require a small amount of RAM that is used to hold the mutex's
|
||||||
|
* state. If a mutex is created using FreeRTOS::Mutex then the required RAM is
|
||||||
|
* automatically allocated from the FreeRTOS heap. If a mutex is created using
|
||||||
|
* FreeRTOS::StaticMutex then the RAM is provided by the application writer and
|
||||||
|
* allows the RAM to be statically allocated at compile time. See the Static Vs
|
||||||
|
* Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* Mutexes and binary semaphores are very similar but have some subtle
|
||||||
|
* differences: Mutexes include a priority inheritance mechanism, binary
|
||||||
|
* semaphores do not. This makes binary semaphores the better choice for
|
||||||
|
* implementing synchronisation (between tasks or between tasks and an
|
||||||
|
* interrupt), and mutexes the better choice for implementing simple mutual
|
||||||
|
* exclusion.
|
||||||
|
*
|
||||||
|
* The priority of a task that locks a mutex will be temporarily raised if
|
||||||
|
* another task of higher priority attempts to obtain the same mutex. The task
|
||||||
|
* that owns the mutex 'inherits' the priority of the task attempting to lock
|
||||||
|
* the same mutex. This means the mutex must always be unlocked back otherwise
|
||||||
|
* the higher priority task will never be able to lock the mutex, and the lower
|
||||||
|
* priority task will never 'disinherit' the priority.
|
||||||
|
*/
|
||||||
|
class Mutex : public MutexBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new Mutex object by calling <tt>SemaphoreHandle_t
|
||||||
|
* xSemaphoreCreateMutex( void )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/CreateMutex.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* mutex was created successfully in case the memory required to create the
|
||||||
|
* queue could not be allocated.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/mutex.cpp
|
||||||
|
*/
|
||||||
|
Mutex() { this->handle = xSemaphoreCreateMutex(); }
|
||||||
|
~Mutex() = default;
|
||||||
|
|
||||||
|
Mutex(const Mutex&) = delete;
|
||||||
|
Mutex& operator=(const Mutex&) = delete;
|
||||||
|
|
||||||
|
Mutex(Mutex&&) noexcept = default;
|
||||||
|
Mutex& operator=(Mutex&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class RecursiveMutex Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS recursive
|
||||||
|
* mutex.
|
||||||
|
*
|
||||||
|
* Each recursive mutex require a small amount of RAM that is used to hold the
|
||||||
|
* recursive mutex's state. If a mutex is created using FreeRTOS::RecursiveMutex
|
||||||
|
* then the required RAM is automatically allocated from the FreeRTOS heap. If a
|
||||||
|
* recursive mutex is created using FreeRTOS::StaticRecursiveMutex then the RAM
|
||||||
|
* is provided by the application writer, which requires an additional
|
||||||
|
* parameter, but allows the RAM to be statically allocated at compile time. See
|
||||||
|
* the Static Vs Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* Contrary to non-recursive mutexes, a task can lock a recursive mutex multiple
|
||||||
|
* times, and the recursive mutex will only be returned after the holding task
|
||||||
|
* has unlocked the mutex the same number of times it locked the mutex.
|
||||||
|
*
|
||||||
|
* Like non-recursive mutexes, recursive mutexes implement a priority
|
||||||
|
* inheritance algorithm. The priority of a task that locks a mutex will be
|
||||||
|
* temporarily raised if another task of higher priority attempts to obtain the
|
||||||
|
* same mutex. The task that owns the mutex 'inherits' the priority of the task
|
||||||
|
* attempting to lock the same mutex. This means the mutex must always be
|
||||||
|
* unlocked otherwise the higher priority task will never be able to obtain the
|
||||||
|
* mutex, and the lower priority task will never 'disinherit' the priority.
|
||||||
|
*/
|
||||||
|
class RecursiveMutex : public RecursiveMutexBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new RecursiveMutex object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateRecursiveMutex.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* recursive mutex was created successfully in case the memory required to
|
||||||
|
* create the queue could not be allocated.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Mutex/recursiveMutex.cpp
|
||||||
|
*/
|
||||||
|
RecursiveMutex() { this->handle = xSemaphoreCreateRecursiveMutex(); }
|
||||||
|
~RecursiveMutex() = default;
|
||||||
|
|
||||||
|
RecursiveMutex(const RecursiveMutex&) = delete;
|
||||||
|
RecursiveMutex& operator=(const RecursiveMutex&) = delete;
|
||||||
|
|
||||||
|
RecursiveMutex(RecursiveMutex&&) noexcept = default;
|
||||||
|
RecursiveMutex& operator=(RecursiveMutex&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticMutex Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS mutex.
|
||||||
|
*
|
||||||
|
* Each mutex require a small amount of RAM that is used to hold the mutex's
|
||||||
|
* state. If a mutex is created using FreeRTOS::Mutex then the required RAM is
|
||||||
|
* automatically allocated from the FreeRTOS heap. If a mutex is created using
|
||||||
|
* FreeRTOS::StaticMutex then the RAM is provided by the application writer and
|
||||||
|
* allows the RAM to be statically allocated at compile time. See the Static Vs
|
||||||
|
* Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* Mutexes and binary semaphores are very similar but have some subtle
|
||||||
|
* differences: Mutexes include a priority inheritance mechanism, binary
|
||||||
|
* semaphores do not. This makes binary semaphores the better choice for
|
||||||
|
* implementing synchronisation (between tasks or between tasks and an
|
||||||
|
* interrupt), and mutexes the better choice for implementing simple mutual
|
||||||
|
* exclusion.
|
||||||
|
*
|
||||||
|
* The priority of a task that locks a mutex will be temporarily raised if
|
||||||
|
* another task of higher priority attempts to obtain the same mutex. The task
|
||||||
|
* that owns the mutex 'inherits' the priority of the task attempting to lock
|
||||||
|
* the same mutex. This means the mutex must always be unlocked back otherwise
|
||||||
|
* the higher priority task will never be able to lock the mutex, and the lower
|
||||||
|
* priority task will never 'disinherit' the priority.
|
||||||
|
*/
|
||||||
|
class StaticMutex : public MutexBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticMutex object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t
|
||||||
|
* *pxMutexBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateMutexStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the mutex, 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 Mutex/staticMutex.cpp
|
||||||
|
*/
|
||||||
|
StaticMutex() { this->handle = xSemaphoreCreateMutexStatic(&staticMutex); }
|
||||||
|
~StaticMutex() = default;
|
||||||
|
|
||||||
|
StaticMutex(const StaticMutex&) = delete;
|
||||||
|
StaticMutex& operator=(const StaticMutex&) = delete;
|
||||||
|
|
||||||
|
StaticMutex(StaticMutex&&) noexcept = default;
|
||||||
|
StaticMutex& operator=(StaticMutex&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticSemaphore_t staticMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticRecursiveMutex Mutex.hpp <FreeRTOS/Mutex.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS recursive
|
||||||
|
* mutex.
|
||||||
|
*
|
||||||
|
* Each recursive mutex require a small amount of RAM that is used to hold the
|
||||||
|
* recursive mutex's state. If a mutex is created using FreeRTOS::RecursiveMutex
|
||||||
|
* then the required RAM is automatically allocated from the FreeRTOS heap. If a
|
||||||
|
* recursive mutex is created using FreeRTOS::StaticRecursiveMutex then the RAM
|
||||||
|
* is provided by the application writer, which requires an additional
|
||||||
|
* parameter, but allows the RAM to be statically allocated at compile time. See
|
||||||
|
* the Static Vs Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* Contrary to non-recursive mutexes, a task can lock a recursive mutex multiple
|
||||||
|
* times, and the recursive mutex will only be returned after the holding task
|
||||||
|
* has unlocked the mutex the same number of times it locked the mutex.
|
||||||
|
*
|
||||||
|
* Like non-recursive mutexes, recursive mutexes implement a priority
|
||||||
|
* inheritance algorithm. The priority of a task that locks a mutex will be
|
||||||
|
* temporarily raised if another task of higher priority attempts to obtain the
|
||||||
|
* same mutex. The task that owns the mutex 'inherits' the priority of the task
|
||||||
|
* attempting to lock the same mutex. This means the mutex must always be
|
||||||
|
* unlocked otherwise the higher priority task will never be able to obtain the
|
||||||
|
* mutex, and the lower priority task will never 'disinherit' the priority.
|
||||||
|
*/
|
||||||
|
class StaticRecursiveMutex : public RecursiveMutexBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Mutex.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticRecursiveMutex object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(
|
||||||
|
* StaticSemaphore_t *pxMutexBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateRecursiveMutexStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the recursive mutex, 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 Mutex/staticRecursiveMutex.cpp
|
||||||
|
*/
|
||||||
|
StaticRecursiveMutex() {
|
||||||
|
this->handle = xSemaphoreCreateRecursiveMutexStatic(&staticRecursiveMutex);
|
||||||
|
}
|
||||||
|
~StaticRecursiveMutex() = default;
|
||||||
|
|
||||||
|
StaticRecursiveMutex(const StaticRecursiveMutex&) = delete;
|
||||||
|
StaticRecursiveMutex& operator=(const StaticRecursiveMutex&) = delete;
|
||||||
|
|
||||||
|
StaticRecursiveMutex(StaticRecursiveMutex&&) noexcept = default;
|
||||||
|
StaticRecursiveMutex& operator=(StaticRecursiveMutex&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticSemaphore_t staticRecursiveMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_MUTEX_HPP
|
||||||
737
source/test/src/FreeRTOSCPP/Queue.hpp
Normal file
737
source/test/src/FreeRTOSCPP/Queue.hpp
Normal file
@ -0,0 +1,737 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
523
source/test/src/FreeRTOSCPP/Semaphore.hpp
Normal file
523
source/test/src/FreeRTOSCPP/Semaphore.hpp
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
/*
|
||||||
|
* 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_SEMAPHORE_HPP
|
||||||
|
#define FREERTOS_SEMAPHORE_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "semphr.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class SemaphoreBase Semaphore.hpp <FreeRTOS/Semaphore.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard semaphore interface to
|
||||||
|
* FreeRTOS::BinarySemaphore, FreeRTOS::StaticBinarySemaphore,
|
||||||
|
* FreeRTOS::CountingSemaphore, and FreeRTOS::StaticCountingSemaphore.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::BinarySemaphore, FreeRTOS::StaticBinarySemaphore,
|
||||||
|
* FreeRTOS::CountingSemaphore, or FreeRTOS::StaticCountingSemaphore.
|
||||||
|
*/
|
||||||
|
class SemaphoreBase {
|
||||||
|
public:
|
||||||
|
friend class BinarySemaphore;
|
||||||
|
friend class StaticBinarySemaphore;
|
||||||
|
friend class CountingSemaphore;
|
||||||
|
friend class StaticCountingSemaphore;
|
||||||
|
|
||||||
|
SemaphoreBase(const SemaphoreBase&) = delete;
|
||||||
|
SemaphoreBase& operator=(const SemaphoreBase&) = 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks if the underlying semaphore handle is not NULL.
|
||||||
|
* This should be used to ensure a semaphore has been created correctly.
|
||||||
|
*
|
||||||
|
* @retval true the handle is not NULL.
|
||||||
|
* @retval false the handle is NULL.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>UBaseType_t uxSemaphoreGetCount(
|
||||||
|
* SemaphoreHandle_t xSemaphore )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/uxSemaphoreGetCount.html>
|
||||||
|
*
|
||||||
|
* Returns the count of a semaphore.
|
||||||
|
*
|
||||||
|
* @return UBaseType_t If the semaphore is a counting semaphore then the
|
||||||
|
* semaphores current count value is returned. If the semaphore is a binary
|
||||||
|
* semaphore then 1 is returned if the semaphore is available, and 0 is
|
||||||
|
* returned if the semaphore is not available.
|
||||||
|
*/
|
||||||
|
inline UBaseType_t getCount() const { return uxSemaphoreGetCount(handle); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTake( SemaphoreHandle_t
|
||||||
|
* xSemaphore, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00122.html>
|
||||||
|
*
|
||||||
|
* Function to obtain a semaphore.
|
||||||
|
*
|
||||||
|
* This macro must not be called from an ISR. takeFromISR() can be used to
|
||||||
|
* take a semaphore from within an interrupt if required, although this would
|
||||||
|
* not be a normal operation. Semaphores use queues as their underlying
|
||||||
|
* mechanism, so functions are to some extent interoperable.
|
||||||
|
*
|
||||||
|
* @param ticksToWait The time in ticks to wait for the semaphore to become
|
||||||
|
* available. The macro portTICK_PERIOD_MS can be used to convert this to a
|
||||||
|
* real time. A block time of zero can be used to poll the semaphore.
|
||||||
|
* @retval true If the semaphore was obtained.
|
||||||
|
* @retval false If xTicksToWait expired without the semaphore becoming
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Semaphore/take.cpp
|
||||||
|
*/
|
||||||
|
inline bool take(const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return (xSemaphoreTake(handle, ticksToWait) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTakeFromISR( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken)</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreTakeFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of take() that can be called from an ISR. Unlike take(),
|
||||||
|
* takeFromISR() does not permit a block time to be specified.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible (although unlikely, and
|
||||||
|
* dependent on the semaphore type) that a semaphore will have one or more
|
||||||
|
* tasks blocked on it waiting to give the semaphore. Calling takeFromISR()
|
||||||
|
* will make a task that was blocked waiting to give the semaphore leave the
|
||||||
|
* Blocked state. If calling the API function causes a task to leave the
|
||||||
|
* Blocked state, and the unblocked task has a priority equal to or higher
|
||||||
|
* than the currently executing task (the task that was interrupted), then,
|
||||||
|
* internally, the API function will set higherPriorityTaskWoken to true. If
|
||||||
|
* takeFromISR() sets higherPriorityTaskWoken to true, then a context switch
|
||||||
|
* should be performed before the interrupt is exited. This will ensure that
|
||||||
|
* the interrupt returns directly to the highest priority Ready state task.
|
||||||
|
* The mechanism is identical to that used in the FreeRTOS::receiveFromISR()
|
||||||
|
* function, and readers are referred to the FreeRTOS::receiveFromISR()
|
||||||
|
* documentation for further explanation.
|
||||||
|
* @retval true If the semaphore was successfully taken.
|
||||||
|
* @retval false If the semaphore was not successfully taken because it was
|
||||||
|
* not available.
|
||||||
|
*/
|
||||||
|
inline bool takeFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xSemaphoreTakeFromISR(handle, &taskWoken) == pdTRUE);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreTakeFromISR( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken)</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreTakeFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool takeFromISR() const {
|
||||||
|
return (xSemaphoreTakeFromISR(handle, NULL) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreGive( SemaphoreHandle_t xSemaphore
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00123.html>
|
||||||
|
*
|
||||||
|
* Function to release a semaphore.
|
||||||
|
*
|
||||||
|
* This must not be used from an ISR. See giveFromISR() for an alternative
|
||||||
|
* which can be used from an ISR.
|
||||||
|
*
|
||||||
|
* @retval true If the semaphore was released.
|
||||||
|
* @retval false If an error occurred. Semaphores are implemented using
|
||||||
|
* queues. An error can occur if there is no space on the queue to post a
|
||||||
|
* message indicating that the semaphore was not first obtained correctly.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Semaphore/give.cpp
|
||||||
|
*/
|
||||||
|
inline bool give() const { return (xSemaphoreGive(handle) == pdTRUE); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreGiveFromISR( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00124.html>
|
||||||
|
*
|
||||||
|
* Function to release a semaphore.
|
||||||
|
*
|
||||||
|
* This macro can be used from an ISR.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken giveFromISR() will set
|
||||||
|
* higherPriorityTaskWoken to true if giving the semaphore caused a task to
|
||||||
|
* unblock, and the unblocked task has a priority higher than the currently
|
||||||
|
* running task. If giveFromISR() sets this value to true then a context
|
||||||
|
* switch should be requested before the interrupt is exited.
|
||||||
|
* @retval true If the semaphore was successfully given.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Semaphore/giveFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool giveFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xSemaphoreGiveFromISR(handle, &taskWoken) == pdTRUE);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>xSemaphoreGiveFromISR( SemaphoreHandle_t
|
||||||
|
* xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00124.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool giveFromISR() const {
|
||||||
|
return (xSemaphoreGiveFromISR(handle, NULL) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SemaphoreBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the SemaphoreBase object by calling <tt>void
|
||||||
|
* vSemaphoreDelete( SemaphoreHandle_t xSemaphore )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/a00113.html#vSemaphoreDelete>
|
||||||
|
*
|
||||||
|
* @note Do not delete a semaphore that has tasks blocked on it (tasks that
|
||||||
|
* are in the Blocked state waiting for the semaphore to become available).
|
||||||
|
*/
|
||||||
|
~SemaphoreBase() { vSemaphoreDelete(this->handle); }
|
||||||
|
|
||||||
|
SemaphoreBase(SemaphoreBase&&) noexcept = default;
|
||||||
|
SemaphoreBase& operator=(SemaphoreBase&&) noexcept = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle used to refer to the semaphore when using the FreeRTOS
|
||||||
|
* interface.
|
||||||
|
*/
|
||||||
|
SemaphoreHandle_t handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class BinarySemaphore Semaphore.hpp <FreeRTOS/Semaphore.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS binary
|
||||||
|
* semaphore.
|
||||||
|
*
|
||||||
|
* Each binary semaphore require a small amount of RAM that is used to hold the
|
||||||
|
* semaphore's state. If a binary semaphore is created using
|
||||||
|
* FreeRTOS::BinarySemaphore then the required RAM is automatically allocated
|
||||||
|
* from the FreeRTOS heap. If a binary semaphore is created using
|
||||||
|
* FreeRTOS::StaticBinarySemaphore then the RAM is provided by the application
|
||||||
|
* writer as part of the class and allows the RAM to be statically allocated at
|
||||||
|
* compile time. See the Static Vs Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* The semaphore is created in the 'empty' state, meaning the semaphore must
|
||||||
|
* first be given using the give() API function before it can subsequently be
|
||||||
|
* taken (obtained) using the take() function.
|
||||||
|
*
|
||||||
|
* Binary semaphores and mutexes are very similar but have some subtle
|
||||||
|
* differences: Mutexes include a priority inheritance mechanism, binary
|
||||||
|
* semaphores do not. This makes binary semaphores the better choice for
|
||||||
|
* implementing synchronisation (between tasks or between tasks and an
|
||||||
|
* interrupt), and mutexes the better choice for implementing simple mutual
|
||||||
|
* exclusion.
|
||||||
|
*
|
||||||
|
* A binary semaphore need not be given back once obtained, so task
|
||||||
|
* synchronisation can be implemented by one task/interrupt continuously
|
||||||
|
* 'giving' the semaphore while another continuously 'takes' the semaphore. This
|
||||||
|
* is demonstrated by the sample code on the giveFromISR() documentation page.
|
||||||
|
* Note the same functionality can often be achieved in a more efficient way
|
||||||
|
* using a direct to task notification.
|
||||||
|
*
|
||||||
|
* The priority of a task that 'takes' a mutex can potentially be raised if
|
||||||
|
* another task of higher priority attempts to obtain the same mutex. The task
|
||||||
|
* that owns the mutex 'inherits' the priority of the task attempting to 'take'
|
||||||
|
* the same mutex. This means the mutex must always be 'given' back - otherwise
|
||||||
|
* the higher priority task will never be able to obtain the mutex, and the
|
||||||
|
* lower priority task will never 'disinherit' the priority. An example of a
|
||||||
|
* mutex being used to implement mutual exclusion is provided on the take()
|
||||||
|
* documentation page.
|
||||||
|
*/
|
||||||
|
class BinarySemaphore : public SemaphoreBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new BinarySemaphore object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateBinary( void )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateBinary.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* binary semaphore was created successfully in case the memory required to
|
||||||
|
* create the queue could not be allocated.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Semaphore/binarySemaphore.cpp
|
||||||
|
*/
|
||||||
|
BinarySemaphore() { this->handle = xSemaphoreCreateBinary(); }
|
||||||
|
~BinarySemaphore() = default;
|
||||||
|
|
||||||
|
BinarySemaphore(const BinarySemaphore&) = delete;
|
||||||
|
BinarySemaphore& operator=(const BinarySemaphore&) = delete;
|
||||||
|
|
||||||
|
BinarySemaphore(BinarySemaphore&&) noexcept = default;
|
||||||
|
BinarySemaphore& operator=(BinarySemaphore&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class CountingSemaphore Semaphore.hpp <FreeRTOS/Semaphore.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS counting
|
||||||
|
* semaphore.
|
||||||
|
*
|
||||||
|
* Each counting semaphore require a small amount of RAM that is used to hold
|
||||||
|
* the semaphore's state. If a counting semaphore is created using
|
||||||
|
* FreeRTOS::CountingSemaphore then the required RAM is automatically allocated
|
||||||
|
* from the FreeRTOS heap. If a counting semaphore is created using
|
||||||
|
* FreeRTOS::StaticCountingSemaphore then the RAM is provided by the application
|
||||||
|
* writer as part of the class and allows the RAM to be statically allocated at
|
||||||
|
* compile time. See the Static Vs Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* Counting semaphores are typically used for two things:
|
||||||
|
* 1. <b>Counting Events:</b>
|
||||||
|
* In this usage scenario an event handler will 'give' a semaphore each time an
|
||||||
|
* event occurs (incrementing the semaphore count value), and a handler task
|
||||||
|
* will 'take' a semaphore each time it processes an event (decrementing the
|
||||||
|
* semaphore count value). The count value is therefore the difference between
|
||||||
|
* the number of events that have occurred and the number that have been
|
||||||
|
* processed. In this case it is desirable for the initial count value to be
|
||||||
|
* zero. Note the same functionality can often be achieved in a more efficient
|
||||||
|
* way using a direct to task notification.
|
||||||
|
*
|
||||||
|
* 2. <b>Resource Management:</b>
|
||||||
|
* In this usage scenario the count value indicates the number of resources
|
||||||
|
* available. To obtain control of a resource a task must first obtain a
|
||||||
|
* semaphore - decrementing the semaphore count value. When the count value
|
||||||
|
* reaches zero there are no free resources. When a task finishes with the
|
||||||
|
* resource it 'gives' the semaphore back - incrementing the semaphore count
|
||||||
|
* value. In this case it is desirable for the initial count value to be equal
|
||||||
|
* to the maximum count value, indicating that all resources are free.
|
||||||
|
*/
|
||||||
|
class CountingSemaphore : public SemaphoreBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new CountingSemaphore by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
|
||||||
|
* UBaseType_t uxInitialCount)</tt>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* binary semaphore was created successfully in case the memory required to
|
||||||
|
* create the queue could not be allocated.
|
||||||
|
*
|
||||||
|
* @param maxCount The maximum count value that can be reached. When the
|
||||||
|
* semaphore reaches this value it can no longer be 'given'.
|
||||||
|
* @param initialCount The count value assigned to the semaphore when
|
||||||
|
* it is created.
|
||||||
|
*/
|
||||||
|
explicit CountingSemaphore(const UBaseType_t maxCount,
|
||||||
|
const UBaseType_t initialCount = 0) {
|
||||||
|
this->handle = xSemaphoreCreateCounting(maxCount, initialCount);
|
||||||
|
}
|
||||||
|
~CountingSemaphore() = default;
|
||||||
|
|
||||||
|
CountingSemaphore(const CountingSemaphore&) = delete;
|
||||||
|
CountingSemaphore& operator=(const CountingSemaphore&) = delete;
|
||||||
|
|
||||||
|
CountingSemaphore(CountingSemaphore&&) noexcept = default;
|
||||||
|
CountingSemaphore& operator=(CountingSemaphore&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticBinarySemaphore Semaphore.hpp <FreeRTOS/Semaphore.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS binary
|
||||||
|
* semaphore.
|
||||||
|
*
|
||||||
|
* Each binary semaphore require a small amount of RAM that is used to hold the
|
||||||
|
* semaphore's state. If a binary semaphore is created using
|
||||||
|
* FreeRTOS::BinarySemaphore then the required RAM is automatically allocated
|
||||||
|
* from the FreeRTOS heap. If a binary semaphore is created using
|
||||||
|
* FreeRTOS::StaticBinarySemaphore then the RAM is provided by the application
|
||||||
|
* writer as part of the class and allows the RAM to be statically allocated at
|
||||||
|
* compile time. See the Static Vs Dynamic allocation page for more information.
|
||||||
|
*
|
||||||
|
* The semaphore is created in the 'empty' state, meaning the semaphore must
|
||||||
|
* first be given using the give() API function before it can subsequently be
|
||||||
|
* taken (obtained) using the take() function.
|
||||||
|
*
|
||||||
|
* Binary semaphores and mutexes are very similar but have some subtle
|
||||||
|
* differences: Mutexes include a priority inheritance mechanism, binary
|
||||||
|
* semaphores do not. This makes binary semaphores the better choice for
|
||||||
|
* implementing synchronisation (between tasks or between tasks and an
|
||||||
|
* interrupt), and mutexes the better choice for implementing simple mutual
|
||||||
|
* exclusion.
|
||||||
|
*
|
||||||
|
* A binary semaphore need not be given back once obtained, so task
|
||||||
|
* synchronisation can be implemented by one task/interrupt continuously
|
||||||
|
* 'giving' the semaphore while another continuously 'takes' the semaphore. This
|
||||||
|
* is demonstrated by the sample code on the giveFromISR() documentation page.
|
||||||
|
* Note the same functionality can often be achieved in a more efficient way
|
||||||
|
* using a direct to task notification.
|
||||||
|
*
|
||||||
|
* The priority of a task that 'takes' a mutex can potentially be raised if
|
||||||
|
* another task of higher priority attempts to obtain the same mutex. The task
|
||||||
|
* that owns the mutex 'inherits' the priority of the task attempting to 'take'
|
||||||
|
* the same mutex. This means the mutex must always be 'given' back - otherwise
|
||||||
|
* the higher priority task will never be able to obtain the mutex, and the
|
||||||
|
* lower priority task will never 'disinherit' the priority. An example of a
|
||||||
|
* mutex being used to implement mutual exclusion is provided on the take()
|
||||||
|
* documentation page.
|
||||||
|
*/
|
||||||
|
class StaticBinarySemaphore : public SemaphoreBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Semaphore.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticBinarySemaphore object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t
|
||||||
|
* *pxSemaphoreBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateBinaryStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the binary semaphore,
|
||||||
|
* 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 Semaphore/staticBinarySemaphore.cpp
|
||||||
|
*/
|
||||||
|
StaticBinarySemaphore() {
|
||||||
|
this->handle = xSemaphoreCreateBinaryStatic(&staticBinarySemaphore);
|
||||||
|
}
|
||||||
|
~StaticBinarySemaphore() = default;
|
||||||
|
|
||||||
|
StaticBinarySemaphore(const StaticBinarySemaphore&) = delete;
|
||||||
|
StaticBinarySemaphore& operator=(const StaticBinarySemaphore&) = delete;
|
||||||
|
|
||||||
|
StaticBinarySemaphore(StaticBinarySemaphore&&) noexcept = default;
|
||||||
|
StaticBinarySemaphore& operator=(StaticBinarySemaphore&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticSemaphore_t staticBinarySemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StaticCountingSemaphore : public SemaphoreBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new StaticCountingSemaphore object by calling
|
||||||
|
* <tt>SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t
|
||||||
|
* uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t
|
||||||
|
* *pxSemaphoreBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xSemaphoreCreateCountingStatic.html>
|
||||||
|
*
|
||||||
|
* @warning This class contains the storage buffer for the counting semaphore,
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param maxCount The maximum count value that can be reached. When the
|
||||||
|
* semaphore reaches this value it can no longer be 'given'.
|
||||||
|
* @param initialCount The count value assigned to the semaphore when it is
|
||||||
|
* created.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Semaphore/staticCountingSemaphore.cpp
|
||||||
|
*/
|
||||||
|
explicit StaticCountingSemaphore(const UBaseType_t maxCount,
|
||||||
|
const UBaseType_t initialCount = 0) {
|
||||||
|
this->handle = xSemaphoreCreateCountingStatic(maxCount, initialCount,
|
||||||
|
&staticCountingSemaphore);
|
||||||
|
}
|
||||||
|
~StaticCountingSemaphore() = default;
|
||||||
|
|
||||||
|
StaticCountingSemaphore(const StaticCountingSemaphore&) = delete;
|
||||||
|
StaticCountingSemaphore& operator=(const StaticCountingSemaphore&) = delete;
|
||||||
|
|
||||||
|
StaticCountingSemaphore(StaticCountingSemaphore&&) noexcept = default;
|
||||||
|
StaticCountingSemaphore& operator=(StaticCountingSemaphore&&) noexcept =
|
||||||
|
default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticSemaphore_t staticCountingSemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_SEMAPHORE_HPP
|
||||||
566
source/test/src/FreeRTOSCPP/StreamBuffer.hpp
Normal file
566
source/test/src/FreeRTOSCPP/StreamBuffer.hpp
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
/*
|
||||||
|
* 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_STREAMBUFFER_HPP
|
||||||
|
#define FREERTOS_STREAMBUFFER_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "stream_buffer.h"
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StreamBufferBase StreamBuffer.hpp <FreeRTOS/StreamBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard stream buffer interface to
|
||||||
|
* FreeRTOS::StreamBuffer and FreeRTOS::StaticStreamBuffer.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. Use
|
||||||
|
* FreeRTOS::StreamBuffer or FreeRTOS::StaticStreamBuffer.
|
||||||
|
*
|
||||||
|
* @warning Uniquely among FreeRTOS objects, the stream buffer implementation
|
||||||
|
* (so also the message buffer implementation, as message buffers are built on
|
||||||
|
* top of stream buffers) assumes there is only one task or interrupt that will
|
||||||
|
* write to the buffer (the writer), and only one task or interrupt that will
|
||||||
|
* read from the buffer (the reader). It is safe for the writer and reader to
|
||||||
|
* be different tasks or interrupts, but, unlike other FreeRTOS objects, it is
|
||||||
|
* not safe to have multiple different writers or multiple different readers. If
|
||||||
|
* there are to be multiple different writers then the application writer must
|
||||||
|
* place each call to a writing API function (such as send()) inside a critical
|
||||||
|
* section and set the send block time to 0. Likewise, if there are to be
|
||||||
|
* multiple different readers then the application writer must place each call
|
||||||
|
* to a reading API function (such as read()) inside a critical section and set
|
||||||
|
* the receive block time to 0.
|
||||||
|
*/
|
||||||
|
class StreamBufferBase {
|
||||||
|
public:
|
||||||
|
friend class StreamBuffer;
|
||||||
|
template <size_t>
|
||||||
|
friend class StaticStreamBuffer;
|
||||||
|
|
||||||
|
StreamBufferBase(const StreamBufferBase&) = delete;
|
||||||
|
StreamBufferBase& operator=(const StreamBufferBase&) = 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks if the underlying stream buffer handle is not
|
||||||
|
* NULL. This should be used to ensure a stream buffer has been created
|
||||||
|
* correctly.
|
||||||
|
*
|
||||||
|
* @retval true If the handle is not NULL.
|
||||||
|
* @retval false If the handle is NULL.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferSend(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferSend.html>
|
||||||
|
*
|
||||||
|
* Sends bytes to a stream buffer. The bytes are copied into the stream
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* Use send() to write to a stream buffer from a task. Use sendFromISR() to
|
||||||
|
* write to a stream buffer from an interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param data A pointer to the buffer that holds the bytes to be copied into
|
||||||
|
* the stream buffer.
|
||||||
|
* @param length The maximum number of bytes to copy from data into the stream
|
||||||
|
* buffer.
|
||||||
|
* @param ticksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for enough space to become available in the stream
|
||||||
|
* buffer, should the stream buffer contain too little space to hold the
|
||||||
|
* another length bytes. The block time is specified in tick periods, so the
|
||||||
|
* absolute time it represents is dependent on the tick frequency. The macro
|
||||||
|
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||||
|
* into a time specified in ticks. Setting ticksToWait to portMAX_DELAY will
|
||||||
|
* cause the task to wait indefinitely (without timing out), provided
|
||||||
|
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. If a task times out
|
||||||
|
* before it can write all length into the buffer it will still write as many
|
||||||
|
* bytes as possible. A task does not use any CPU time when it is in the
|
||||||
|
* blocked state.
|
||||||
|
* @return size_t The number of bytes written to the stream buffer. If a task
|
||||||
|
* times out before it can write all length into the buffer it will still
|
||||||
|
* write as many bytes as possible.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/send.cpp
|
||||||
|
*/
|
||||||
|
inline size_t send(const void* data, const size_t length,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return xStreamBufferSend(handle, data, length, ticksToWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferSendFromISR(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferSendFromISR.html>
|
||||||
|
*
|
||||||
|
* Interrupt safe version of the API function that sends a stream of bytes to
|
||||||
|
* the stream buffer.
|
||||||
|
*
|
||||||
|
* Use send() to write to a stream buffer from a task. Use sendFromISR() to
|
||||||
|
* write to a stream buffer from an interrupt service routine (ISR).
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible that a stream buffer will
|
||||||
|
* have a task blocked on it waiting for data. Calling sendFromISR() can make
|
||||||
|
* data available, and so cause a task that was waiting for data to leave the
|
||||||
|
* Blocked state. If calling sendFromISR() causes a task to leave the Blocked
|
||||||
|
* state, and the unblocked task has a priority higher than the currently
|
||||||
|
* executing task (the task that was interrupted), then, internally,
|
||||||
|
* sendFromISR() will set higherPriorityTaskWoken to true. If sendFromISR()
|
||||||
|
* sets this value to true, then normally a context switch should be performed
|
||||||
|
* before the interrupt is exited. This will ensure that the interrupt
|
||||||
|
* returns directly to the highest priority Ready state task.
|
||||||
|
* higherPriorityTaskWoken should be set to false before it is passed into the
|
||||||
|
* function. See the example code below for an example.
|
||||||
|
* @param data A pointer to the buffer that holds the bytes to be copied into
|
||||||
|
* the stream buffer.
|
||||||
|
* @param length The maximum number of bytes to copy from data into the stream
|
||||||
|
* buffer.
|
||||||
|
* @return size_t The number of bytes written to the stream buffer. If a task
|
||||||
|
* times out before it can write all length into the buffer it will still
|
||||||
|
* write as many bytes as possible.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/sendFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline size_t sendFromISR(bool& higherPriorityTaskWoken, const void* data,
|
||||||
|
const size_t length) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
size_t result = xStreamBufferSendFromISR(handle, data, length, &taskWoken);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferSendFromISR(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t
|
||||||
|
* xDataLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferSendFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline size_t sendFromISR(const void* data, const size_t length) const {
|
||||||
|
return xStreamBufferSendFromISR(handle, data, length, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferReceive(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, TickType_t xTicksToWait )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferReceive.html>
|
||||||
|
*
|
||||||
|
* Receives bytes from a stream buffer.
|
||||||
|
*
|
||||||
|
* Use receive() to read from a stream buffer from a task. Use
|
||||||
|
* receiveFromISR() to read from a stream buffer from an interrupt service
|
||||||
|
* routine (ISR).
|
||||||
|
*
|
||||||
|
* @param buffer A pointer to the buffer into which the received bytes will be
|
||||||
|
* copied.
|
||||||
|
* @param bufferLength The length of the buffer pointed to by the data
|
||||||
|
* parameter. This sets the maximum number of bytes to receive in one call.
|
||||||
|
* receive() will return as many bytes as possible up to a maximum set by
|
||||||
|
* length.
|
||||||
|
* @param ticksToWait The maximum amount of time the task should remain in the
|
||||||
|
* Blocked state to wait for data to become available if the stream buffer is
|
||||||
|
* empty. receive() will return immediately if ticksToWait is zero. The block
|
||||||
|
* time is specified in tick periods, so the absolute time it represents is
|
||||||
|
* dependent on the tick frequency. The macro pdMS_TO_TICKS() can be used to
|
||||||
|
* convert a time specified in milliseconds into a time specified in ticks.
|
||||||
|
* Setting ticksToWait to portMAX_DELAY will cause the task to wait
|
||||||
|
* indefinitely (without timing out), provided INCLUDE_vTaskSuspend is set to
|
||||||
|
* 1 in FreeRTOSConfig.h. A task does not use any CPU time when it is in the
|
||||||
|
* Blocked state.
|
||||||
|
* @return size_t The number of bytes read from the stream buffer. This will
|
||||||
|
* be the number of bytes available up to a maximum of length.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/receive.cpp
|
||||||
|
*/
|
||||||
|
inline size_t receive(void* buffer, const size_t bufferLength,
|
||||||
|
const TickType_t ticksToWait = portMAX_DELAY) const {
|
||||||
|
return xStreamBufferReceive(handle, buffer, bufferLength, ticksToWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferReceiveFromISR(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferReceiveFromISR.html>
|
||||||
|
*
|
||||||
|
* An interrupt safe version of the API function that receives bytes from a
|
||||||
|
* stream buffer.
|
||||||
|
*
|
||||||
|
* Use receive() to read from a stream buffer from a task. Use
|
||||||
|
* receiveFromISR() to read from a stream buffer from an interrupt service
|
||||||
|
* routine (ISR).
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken It is possible that a stream buffer will
|
||||||
|
* have a task blocked on it waiting for space to become available. Calling
|
||||||
|
* receiveFromISR() can make space available, and so cause a task that is
|
||||||
|
* waiting for space to leave the Blocked state. If calling receiveFromISR()
|
||||||
|
* causes a task to leave the Blocked state, and the unblocked task has a
|
||||||
|
* priority higher than the currently executing task (the task that was
|
||||||
|
* interrupted), then, internally, receiveFromISR() will set
|
||||||
|
* higherPriorityTaskWoken to true. If receiveFromISR() sets this value to
|
||||||
|
* true, then normally a context switch should be performed before the
|
||||||
|
* interrupt is exited. That will ensure the interrupt returns directly to the
|
||||||
|
* highest priority Ready state task. higherPriorityTaskWoken should be set to
|
||||||
|
* false before it is passed into the function. See the code example below for
|
||||||
|
* an example.
|
||||||
|
* @param buffer A pointer to the buffer into which the received bytes will be
|
||||||
|
* copied.
|
||||||
|
* @param bufferLength The length of the buffer pointed to by the buffer
|
||||||
|
* parameter. This sets the maximum number of bytes to receive in one call.
|
||||||
|
* receive() will return as many bytes as possible up to a maximum set by
|
||||||
|
* length.
|
||||||
|
* @return size_t The number of bytes read from the stream buffer, if any.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/receiveFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline size_t receiveFromISR(bool& higherPriorityTaskWoken, void* buffer,
|
||||||
|
const size_t bufferLength) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
size_t result =
|
||||||
|
xStreamBufferReceiveFromISR(handle, buffer, bufferLength, &taskWoken);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferReceiveFromISR(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t
|
||||||
|
* xBufferLengthBytes, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferReceiveFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline size_t receiveFromISR(void* buffer, const size_t bufferLength) const {
|
||||||
|
return xStreamBufferReceiveFromISR(handle, buffer, bufferLength, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferBytesAvailable(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferBytesAvailable.html>
|
||||||
|
*
|
||||||
|
* Queries the stream buffer to see how much data it contains, which is equal
|
||||||
|
* to the number of bytes that can be read from the stream buffer before the
|
||||||
|
* stream buffer would be empty.
|
||||||
|
*
|
||||||
|
* @return size_t The number of bytes that can be read from the stream buffer
|
||||||
|
* before the stream buffer would be empty.
|
||||||
|
*/
|
||||||
|
inline size_t bytesAvailable() const {
|
||||||
|
return xStreamBufferBytesAvailable(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>size_t xStreamBufferSpacesAvailable(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferSpacesAvailable.html>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see how much free space it contains, which is
|
||||||
|
* equal to the amount of data that can be sent to the stream buffer before it
|
||||||
|
* is full.
|
||||||
|
*
|
||||||
|
* @return size_t The number of bytes that can be written to the stream buffer
|
||||||
|
* before the stream buffer would be full.
|
||||||
|
*/
|
||||||
|
inline size_t spacesAvailable() const {
|
||||||
|
return xStreamBufferSpacesAvailable(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xStreamBufferSetTriggerLevel(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferSetTriggerLevel.html>
|
||||||
|
*
|
||||||
|
* A stream buffer's trigger level is the number of bytes that must be in the
|
||||||
|
* stream buffer before a task that is blocked on the stream buffer to wait
|
||||||
|
* for data is moved out of the blocked state. For example, if a task is
|
||||||
|
* blocked on a read of an empty stream buffer that has a trigger level of 1
|
||||||
|
* then the task will be unblocked when a single byte is written to the buffer
|
||||||
|
* or the task's block time expires. As another example, if a task is blocked
|
||||||
|
* on a read of an empty stream buffer that has a trigger level of 10 then the
|
||||||
|
* task will not be unblocked until the stream buffer contains at least 10
|
||||||
|
* bytes or the task's block time expires. If a reading task's block time
|
||||||
|
* expires before the trigger level is reached then the task will still
|
||||||
|
* receive however many bytes are actually available. Setting a trigger level
|
||||||
|
* of 0 will result in a trigger level of 1 being used. It is not valid to
|
||||||
|
* specify a trigger level that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* @param triggerLevel The new trigger level for the stream buffer.
|
||||||
|
* @retval true If triggerLevel was less than or equal to the stream buffer's
|
||||||
|
* length then the trigger level was updated.
|
||||||
|
* @retval false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool setTriggerLevel(const size_t triggerLevel = 0) const {
|
||||||
|
return (xStreamBufferSetTriggerLevel(handle, triggerLevel) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xStreamBufferReset(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferReset.html>
|
||||||
|
*
|
||||||
|
* Resets a stream buffer to its initial, empty, state. Any data that was in
|
||||||
|
* the stream buffer is discarded. A stream buffer can only be reset if there
|
||||||
|
* are no tasks blocked waiting to either send to or receive from the stream
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* @return true If the stream buffer is reset.
|
||||||
|
* @return false If there was a task blocked waiting to send to or read from
|
||||||
|
* the stream buffer then the stream buffer was not reset.
|
||||||
|
*/
|
||||||
|
inline bool reset() const { return (xStreamBufferReset(handle) == pdPASS); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xStreamBufferIsEmpty(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferIsEmpty.html>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see if it is empty. A stream buffer is empty if
|
||||||
|
* it does not contain any data.
|
||||||
|
*
|
||||||
|
* @return true If the stream buffer is empty.
|
||||||
|
* @return false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool isEmpty() const {
|
||||||
|
return (xStreamBufferIsEmpty(handle) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xStreamBufferIsFull(
|
||||||
|
* StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferIsFull.html>
|
||||||
|
*
|
||||||
|
* Queries a stream buffer to see if it is full. A stream buffer is full if it
|
||||||
|
* does not have any free space, and therefore cannot accept any more data.
|
||||||
|
*
|
||||||
|
* @return true If the stream buffer is full.
|
||||||
|
* @return false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool isFull() const { return (xStreamBufferIsFull(handle) == pdTRUE); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StreamBufferBase() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the StreamBufferBase object by calling
|
||||||
|
* <tt>void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/vStreamBufferDelete.html>
|
||||||
|
*
|
||||||
|
* Deletes a stream buffer and free the allocated memory.
|
||||||
|
*/
|
||||||
|
~StreamBufferBase() { vStreamBufferDelete(this->handle); }
|
||||||
|
|
||||||
|
StreamBufferBase(StreamBufferBase&&) noexcept = default;
|
||||||
|
StreamBufferBase& operator=(StreamBufferBase&&) noexcept = default;
|
||||||
|
|
||||||
|
StreamBufferHandle_t handle = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StreamBuffer StreamBuffer.hpp <FreeRTOS/StreamBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS stream buffer.
|
||||||
|
*
|
||||||
|
* A stream buffer using dynamically allocated memory from the FreeRTOS heap.
|
||||||
|
* See FreeRTOS::StaticStreamBuffer for a version that uses statically allocated
|
||||||
|
* memory (memory that is allocated at compile time).
|
||||||
|
*/
|
||||||
|
class StreamBuffer : public StreamBufferBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StreamBuffer object by calling
|
||||||
|
* <tt>StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes,
|
||||||
|
* size_t xTriggerLevelBytes )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferCreate.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* stream buffer was created successfully in case the memory required to
|
||||||
|
* create the message buffer could not be allocated.
|
||||||
|
*
|
||||||
|
* @param size The total number of bytes the stream buffer will be able to
|
||||||
|
* hold at any one time.
|
||||||
|
* @param triggerLevel The number of bytes that must be in the stream
|
||||||
|
* buffer before a task that is blocked on the stream buffer to wait for data
|
||||||
|
* is moved out of the blocked state. For example, if a task is blocked on a
|
||||||
|
* read of an empty stream buffer that has a trigger level of 1 then the task
|
||||||
|
* will be unblocked when a single byte is written to the buffer or the task's
|
||||||
|
* block time expires. As another example, if a task is blocked on a read of
|
||||||
|
* an empty stream buffer that has a trigger level of 10 then the task will
|
||||||
|
* not be unblocked until the stream buffer contains at least 10 bytes or the
|
||||||
|
* task's block time expires. If a reading task's block time expires before
|
||||||
|
* the trigger level is reached then the task will still receive however many
|
||||||
|
* bytes are actually available. Setting a trigger level of 0 will result in a
|
||||||
|
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||||
|
* that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/streamBuffer.cpp
|
||||||
|
*/
|
||||||
|
explicit StreamBuffer(const size_t size, const size_t triggerLevel = 0) {
|
||||||
|
this->handle = xStreamBufferCreate(size, triggerLevel);
|
||||||
|
}
|
||||||
|
~StreamBuffer() = default;
|
||||||
|
|
||||||
|
StreamBuffer(const StreamBuffer&) = delete;
|
||||||
|
StreamBuffer& operator=(const StreamBuffer&) = delete;
|
||||||
|
|
||||||
|
StreamBuffer(StreamBuffer&&) noexcept = default;
|
||||||
|
StreamBuffer& operator=(StreamBuffer&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class StaticStreamBuffer StreamBuffer.hpp <FreeRTOS/StreamBuffer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS stream buffer.
|
||||||
|
*
|
||||||
|
* If a stream buffer 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 N The size, in bytes, of the storage buffer for the stream buffer.
|
||||||
|
*/
|
||||||
|
template <size_t N>
|
||||||
|
class StaticStreamBuffer : public StreamBufferBase {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* StreamBuffer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticStreamBuffer object by calling
|
||||||
|
* <tt>StreamBufferHandle_t xStreamBufferCreateStatic( size_t
|
||||||
|
* xBufferSizeBytes, size_t xTriggerLevelBytes, uint8_t
|
||||||
|
* *pucStreamBufferStorageArea, StaticStreamBuffer_t *pxStaticStreamBuffer
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xStreamBufferCreateStatic.html>
|
||||||
|
*
|
||||||
|
* @param triggerLevel The number of bytes that must be in the stream
|
||||||
|
* buffer before a task that is blocked on the stream buffer to wait for data
|
||||||
|
* is moved out of the blocked state. For example, if a task is blocked on a
|
||||||
|
* read of an empty stream buffer that has a trigger level of 1 then the task
|
||||||
|
* will be unblocked when a single byte is written to the buffer or the task's
|
||||||
|
* block time expires. As another example, if a task is blocked on a read of
|
||||||
|
* an empty stream buffer that has a trigger level of 10 then the task will
|
||||||
|
* not be unblocked until the stream buffer contains at least 10 bytes or the
|
||||||
|
* task's block time expires. If a reading task's block time expires before
|
||||||
|
* the trigger level is reached then the task will still receive however many
|
||||||
|
* bytes are actually available. Setting a trigger level of 0 will result in a
|
||||||
|
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||||
|
* that is greater than the buffer size.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include StreamBuffer/staticStreamBuffer.cpp
|
||||||
|
*/
|
||||||
|
explicit StaticStreamBuffer(const size_t triggerLevel = 0) {
|
||||||
|
this->handle = xStreamBufferCreateStatic(sizeof(storage), triggerLevel,
|
||||||
|
storage, &staticStreamBuffer);
|
||||||
|
}
|
||||||
|
~StaticStreamBuffer() = default;
|
||||||
|
|
||||||
|
StaticStreamBuffer(const StaticStreamBuffer&) = delete;
|
||||||
|
StaticStreamBuffer& operator=(const StaticStreamBuffer&) = delete;
|
||||||
|
|
||||||
|
StaticStreamBuffer(StaticStreamBuffer&&) noexcept = default;
|
||||||
|
StaticStreamBuffer& operator=(StaticStreamBuffer&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticStreamBuffer_t staticStreamBuffer;
|
||||||
|
uint8_t storage[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
#endif // FREERTOS_STREAMBUFFER_HPP
|
||||||
1480
source/test/src/FreeRTOSCPP/Task.hpp
Normal file
1480
source/test/src/FreeRTOSCPP/Task.hpp
Normal file
File diff suppressed because it is too large
Load Diff
928
source/test/src/FreeRTOSCPP/Timer.hpp
Normal file
928
source/test/src/FreeRTOSCPP/Timer.hpp
Normal file
@ -0,0 +1,928 @@
|
|||||||
|
/*
|
||||||
|
* 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_TIMER_HPP
|
||||||
|
#define FREERTOS_TIMER_HPP
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief C function that is used to interface this class with the FreeRTOS
|
||||||
|
* kernel.
|
||||||
|
*
|
||||||
|
* @note This function should not be called or referenced by the user.
|
||||||
|
*
|
||||||
|
* @param task Pointer to an instance of FreeRTOS::TimerBase.
|
||||||
|
*/
|
||||||
|
void callTimerFunction(TimerHandle_t timer);
|
||||||
|
|
||||||
|
namespace FreeRTOS {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TimerBase Timer.hpp <FreeRTOS/Timer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Base class that provides the standard task interface to
|
||||||
|
* FreeRTOS::Timer and FreeRTOS::StaticTimer.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated or derived from by the
|
||||||
|
* user. Use FreeRTOS::Timer or FreeRTOS::StaticTimer as a base class for a user
|
||||||
|
* implemented task.
|
||||||
|
*/
|
||||||
|
class TimerBase {
|
||||||
|
public:
|
||||||
|
friend class Timer;
|
||||||
|
friend class StaticTimer;
|
||||||
|
|
||||||
|
TimerBase(const TimerBase&) = delete;
|
||||||
|
TimerBase& operator=(const TimerBase&) = 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that acts as the entry point of the timer instance.
|
||||||
|
*
|
||||||
|
* @note This function is only public so that it can be accessed by the C
|
||||||
|
* interface function <tt>callTimerFunction()</tt> and should not be called or
|
||||||
|
* referenced by the user.
|
||||||
|
*/
|
||||||
|
virtual inline void timerEntry() final { timerFunction(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that checks the value of the timer handle. This function
|
||||||
|
* should be called to ensure the timer was created successfully.
|
||||||
|
*
|
||||||
|
* @return true If the timer was created successfully.
|
||||||
|
* @return false If the timer was not created successfully due to insufficient
|
||||||
|
* memory.
|
||||||
|
*/
|
||||||
|
inline bool isValid() const { return (handle != NULL); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerIsTimerActive(
|
||||||
|
* TimerHandle_t xTimer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerIsTimerActive.html>
|
||||||
|
*
|
||||||
|
* Queries a software timer to see if it is active or dormant.
|
||||||
|
*
|
||||||
|
* A timer will be dormant if:
|
||||||
|
* -# It has been created but not started, or
|
||||||
|
* -# It is an expired one-shot timer that has not been restarted.
|
||||||
|
*
|
||||||
|
* @note Timers are created in the dormant state. The start(), reset(),
|
||||||
|
* startFromISR(), resetFromISR(), changePeriod() and changePeriodFromISR()
|
||||||
|
* API functions can all be used to transition a timer into the active state.
|
||||||
|
*
|
||||||
|
* @return false If the timer is dormant.
|
||||||
|
* @return true Otherwise.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/isActive.cpp
|
||||||
|
*/
|
||||||
|
inline bool isActive() const {
|
||||||
|
return (xTimerIsTimerActive(handle) != pdFALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStart( TimerHandle_t
|
||||||
|
* xTimer, TickType_t xBlockTime )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStart.html>
|
||||||
|
*
|
||||||
|
* start() starts a timer. If the timer had already been started and was
|
||||||
|
* already in the active state, then start() has equivalent functionality to
|
||||||
|
* the reset() API function.
|
||||||
|
*
|
||||||
|
* Starting a timer ensures the timer is in the active state. If the timer is
|
||||||
|
* not stopped, deleted, or reset in the mean time, timerFunction() will get
|
||||||
|
* called 'n 'ticks after start() was called, where 'n' is the timers defined
|
||||||
|
* period.
|
||||||
|
*
|
||||||
|
* It is valid to call start() before the RTOS scheduler has been started, but
|
||||||
|
* when this is done the timer will not actually start until the RTOS
|
||||||
|
* scheduler is started, and the timers expiry time will be relative to when
|
||||||
|
* the RTOS scheduler is started, not relative to when start() was called.
|
||||||
|
*
|
||||||
|
* @param blockTime Specifies the time, in ticks, that the calling task should
|
||||||
|
* be held in the Blocked state to wait for the start command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when start() was called. blockTime is ignored if start() is called
|
||||||
|
* before the RTOS scheduler is started.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system,
|
||||||
|
* although the timers expiry time is relative to when start() is actually
|
||||||
|
* called. The timer service/daemon task priority is set by the
|
||||||
|
* configTIMER_TASK_PRIORITY configuration constant.
|
||||||
|
* @return false If the start command could not be sent to the timer command
|
||||||
|
* queue even after blockTime ticks had passed.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/timer.cpp
|
||||||
|
*/
|
||||||
|
inline bool start(const TickType_t blockTime = 0) const {
|
||||||
|
return (xTimerStart(handle, blockTime) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStartFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStartFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of start() that can be called from an interrupt service routine.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken The timer service/daemon task spends most of
|
||||||
|
* its time in the Blocked state, waiting for messages to arrive on the timer
|
||||||
|
* command queue. Calling startFromISR() writes a message to the timer command
|
||||||
|
* queue, so has the potential to transition the timer service/daemon task out
|
||||||
|
* of the Blocked state. If calling startFromISR() causes the timer
|
||||||
|
* service/daemon task to leave the Blocked state, and the timer service/
|
||||||
|
* daemon task has a priority equal to or greater than the currently executing
|
||||||
|
* task (the task that was interrupted), then higherPriorityTaskWoken will get
|
||||||
|
* set to true internally within the startFromISR() function. If
|
||||||
|
* startFromISR() sets this value to true, then a context switch should be
|
||||||
|
* performed before the interrupt exits.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system,
|
||||||
|
* although the timers expiry time is relative to when startFromISR() is
|
||||||
|
* actually called. The timer service/daemon task priority is set by the
|
||||||
|
* configTIMER_TASK_PRIORITY configuration constant.
|
||||||
|
* @return false If the start command could not be sent to the timer command
|
||||||
|
* queue.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/startFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool startFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xTimerStartFromISR(handle, &taskWoken) == pdPASS);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStartFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStartFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool startFromISR() const {
|
||||||
|
return (xTimerStartFromISR(handle, NULL) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStop( TimerHandle_t xTimer,
|
||||||
|
* TickType_t xBlockTime )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStop.html>
|
||||||
|
*
|
||||||
|
* stop() stops a timer that was previously started using either of the
|
||||||
|
* start(), reset(), startFromISR(), resetFromISR(), changePeriod() and
|
||||||
|
* changePeriodFromISR() API functions.
|
||||||
|
*
|
||||||
|
* Stopping a timer ensures the timer is not in the active state.
|
||||||
|
*
|
||||||
|
* @param blockTime Specifies the time, in ticks, that the calling task should
|
||||||
|
* be held in the Blocked state to wait for the stop command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when stop() was called. blockTime is ignored if stop() is called
|
||||||
|
* before the RTOS scheduler is started.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system. The
|
||||||
|
* timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
|
||||||
|
* configuration constant.
|
||||||
|
* @return false If the stop command could not be sent to the timer command
|
||||||
|
* queue even after blockTime ticks had passed.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/timer.cpp
|
||||||
|
*/
|
||||||
|
inline bool stop(const TickType_t blockTime = 0) const {
|
||||||
|
return (xTimerStop(handle, blockTime) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStopFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStopFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of stop() that can be called from an interrupt service routine.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken The timer service/daemon task spends most of
|
||||||
|
* its time in the Blocked state, waiting for messages to arrive on the timer
|
||||||
|
* command queue. Calling stopFromISR() writes a message to the timer command
|
||||||
|
* queue, so has the potential to transition the timer service/daemon task out
|
||||||
|
* of the Blocked state. If calling stopFromISR() causes the timer
|
||||||
|
* service/daemon task to leave the Blocked state, and the timer service/
|
||||||
|
* daemon task has a priority equal to or greater than the currently executing
|
||||||
|
* task (the task that was interrupted), then higherPriorityTaskWoken will get
|
||||||
|
* set to true internally within the stopFromISR() function. If stopFromISR()
|
||||||
|
* sets this value to true, then a context switch should be performed before
|
||||||
|
* the interrupt exits.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system. The
|
||||||
|
* timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
|
||||||
|
* configuration constant.
|
||||||
|
* @return false If the start command could not be sent to the timer command
|
||||||
|
* queue.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/stopFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool stopFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xTimerStopFromISR(handle, &taskWoken) == pdPASS);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerStopFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerStopFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool stopFromISR() const {
|
||||||
|
return (xTimerStopFromISR(handle, NULL) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerChangePeriod( TimerHandle_t
|
||||||
|
* xTimer, TickType_t xNewPeriod, TickType_t xBlockTime )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerChangePeriod.html>
|
||||||
|
*
|
||||||
|
* changePeriod() changes the period of a timer.
|
||||||
|
*
|
||||||
|
* changePeriod() can be called to change the period of an active or dormant
|
||||||
|
* state timer. Changing the period of a dormant timers will also start the
|
||||||
|
* timer.
|
||||||
|
*
|
||||||
|
* @param newPeriod The new period for timer. Timer periods are specified in
|
||||||
|
* tick periods, so the constant portTICK_PERIOD_MS can be used to convert a
|
||||||
|
* time that has been specified in milliseconds. For example, if the timer
|
||||||
|
* must expire after 100 ticks, then newPeriod should be set to 100.
|
||||||
|
* Alternatively, if the timer must expire after 500ms, then newPeriod can be
|
||||||
|
* set to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less
|
||||||
|
* than or equal to 1000.
|
||||||
|
* @param blockTime Specifies the time, in ticks, that the calling task should
|
||||||
|
* be held in the Blocked state to wait for the change period command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when changePeriod() was called. blockTime is ignored if changePeriod()
|
||||||
|
* is called before the RTOS scheduler is started.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system. The
|
||||||
|
* timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
|
||||||
|
* configuration constant.
|
||||||
|
* @return false If the change period command could not be sent to the timer
|
||||||
|
* command queue even after blockTime ticks had passed.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/changePeriod.cpp
|
||||||
|
*/
|
||||||
|
inline bool changePeriod(const TickType_t newPeriod,
|
||||||
|
const TickType_t blockTime = 0) const {
|
||||||
|
return (xTimerChangePeriod(handle, newPeriod, blockTime) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerChangePeriodFromISR(
|
||||||
|
* TimerHandle_t xTimer, TickType_t xNewPeriod, BaseType_t
|
||||||
|
* *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <https://www.freertos.org/FreeRTOS-timers-xTimerChangePeriodFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of changePeriod() that can be called from an interrupt service
|
||||||
|
* routine.
|
||||||
|
*
|
||||||
|
* @param newPeriod The new period for timer. Timer periods are specified in
|
||||||
|
* tick periods, so the constant portTICK_PERIOD_MS can be used to convert a
|
||||||
|
* time that has been specified in milliseconds. For example, if the timer
|
||||||
|
* must expire after 100 ticks, then newPeriod should be set to 100.
|
||||||
|
* Alternatively, if the timer must expire after 500ms, then newPeriod can be
|
||||||
|
* set to ( 500 / portTICK_PERIOD_MS ) provided configTICK_RATE_HZ is less
|
||||||
|
* than or equal to 1000.
|
||||||
|
* @param higherPriorityTaskWoken The timer service/daemon task spends most of
|
||||||
|
* its time in the Blocked state, waiting for messages to arrive on the timer
|
||||||
|
* command queue. Calling changePeriodFromISR() writes a message to the timer
|
||||||
|
* command queue, so has the potential to transition the timer service/ daemon
|
||||||
|
* task out of the Blocked state. If calling changePeriodFromISR() causes the
|
||||||
|
* timer service/daemon task to leave the Blocked state, and the timer
|
||||||
|
* service/daemon task has a priority equal to or greater than the currently
|
||||||
|
* executing task (the task that was interrupted), then
|
||||||
|
* higherPriorityTaskWoken will get set to true internally within the
|
||||||
|
* changePeriodFromISR() function. If changePeriodFromISR() sets this value to
|
||||||
|
* true, then a context switch should be performed before the interrupt exits.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system. The
|
||||||
|
* timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
|
||||||
|
* configuration constant.
|
||||||
|
* @return false If the change period command could not be sent to the timer
|
||||||
|
* command queue.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/changePeriodFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool changePeriodFromISR(bool& higherPriorityTaskWoken,
|
||||||
|
const TickType_t newPeriod) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result =
|
||||||
|
(xTimerChangePeriodFromISR(handle, newPeriod, &taskWoken) == pdPASS);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerChangePeriodFromISR(
|
||||||
|
* TimerHandle_t xTimer, TickType_t xNewPeriod, BaseType_t
|
||||||
|
* *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <https://www.freertos.org/FreeRTOS-timers-xTimerChangePeriodFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool changePeriodFromISR(const TickType_t newPeriod) const {
|
||||||
|
return (xTimerChangePeriodFromISR(handle, newPeriod, NULL) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerDelete( TimerHandle_t
|
||||||
|
* xTimer, TickType_t xBlockTime )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerDelete.html>
|
||||||
|
*
|
||||||
|
* deleteTimer() deletes a timer from the FreeRTOS timer task.
|
||||||
|
*
|
||||||
|
* @note This function is also called in the destructor of the timer using the
|
||||||
|
* deleteBlockTime specified when the object was created. This function
|
||||||
|
* should be used when the user wants to delete the timer from the FreeRTOS
|
||||||
|
* timer task without destroying the timer object or with a different block
|
||||||
|
* time than what was specified in the constructor.
|
||||||
|
*
|
||||||
|
* @param blockTime Specifies the time, in ticks, that the calling task should
|
||||||
|
* be held in the Blocked state to wait for the delete command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when deleteTimer() was called. blockTime is ignored if deleteTimer()
|
||||||
|
* is called before the RTOS scheduler is started.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system. The
|
||||||
|
* timer service/daemon task priority is set by the configTIMER_TASK_PRIORITY
|
||||||
|
* configuration constant.
|
||||||
|
* @return false If the delete command could not be sent to the timer command
|
||||||
|
* queue even after blockTime ticks had passed.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/changePeriod.cpp
|
||||||
|
*/
|
||||||
|
inline bool deleteTimer(const TickType_t blockTime = 0) {
|
||||||
|
if (xTimerDelete(handle, blockTime) == pdPASS) {
|
||||||
|
handle = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt> BaseType_t xTimerReset( TimerHandle_t
|
||||||
|
* xTimer, TickType_t xBlockTime )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerReset.html>
|
||||||
|
*
|
||||||
|
* reset() re-starts a timer. If the timer had already been started and was
|
||||||
|
* already in the active state, then reset() will cause the timer to
|
||||||
|
* re-evaluate its expiry time so that it is relative to when reset() was
|
||||||
|
* called. If the timer was in the dormant state then reset() has equivalent
|
||||||
|
* functionality to the start() API function.
|
||||||
|
*
|
||||||
|
* Resetting a timer ensures the timer is in the active state. If the timer
|
||||||
|
* is not stopped, deleted, or reset in the mean time, the callback function
|
||||||
|
* associated with the timer will get called 'n' ticks after reset() was
|
||||||
|
* called, where 'n' is the timers defined period.
|
||||||
|
*
|
||||||
|
* It is valid to call reset() before the RTOS scheduler has been started, but
|
||||||
|
* when this is done the timer will not actually start until the RTOS
|
||||||
|
* scheduler is started, and the timers expiry time will be relative to when
|
||||||
|
* the RTOS scheduler is started, not relative to when reset() was called.
|
||||||
|
*
|
||||||
|
* @param blockTime Specifies the time, in ticks, that the calling task should
|
||||||
|
* be held in the Blocked state to wait for the reset command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when reset() was called. blockTime is ignored if reset() is called
|
||||||
|
* before the RTOS scheduler is started.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system,
|
||||||
|
* although the timers expiry time is relative to when reset() is actually
|
||||||
|
* called. The timer service/daemon task priority is set by the
|
||||||
|
* configTIMER_TASK_PRIORITY configuration constant.
|
||||||
|
* @return false If the reset command could not be sent to the timer command
|
||||||
|
* queue even after blockTime ticks had passed.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/reset.cpp
|
||||||
|
*/
|
||||||
|
inline bool reset(const TickType_t blockTime = 0) const {
|
||||||
|
return (xTimerReset(handle, blockTime) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerResetFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerResetFromISR.html>
|
||||||
|
*
|
||||||
|
* A version of reset() that can be called from an interrupt service routine.
|
||||||
|
*
|
||||||
|
* @param higherPriorityTaskWoken The timer service/daemon task spends most of
|
||||||
|
* its time in the Blocked state, waiting for messages to arrive on the timer
|
||||||
|
* command queue. Calling resetFromISR() writes a message to the timer command
|
||||||
|
* queue, so has the potential to transition the timer service/daemon task out
|
||||||
|
* of the Blocked state. If calling resetFromISR() causes the timer
|
||||||
|
* service/daemon task to leave the Blocked state, and the timer
|
||||||
|
* service/daemon task has a priority equal to or greater than the currently
|
||||||
|
* executing task (the task that was interrupted), then
|
||||||
|
* higherPriorityTaskWoken will get set to true internally within the
|
||||||
|
* resetFromISR() function. If resetFromISR() sets this value to true, then a
|
||||||
|
* context switch should be performed before the interrupt exits.
|
||||||
|
* @return true If the command was successfully sent to the timer command
|
||||||
|
* queue. When the command is actually processed will depend on the priority
|
||||||
|
* of the timer service/daemon task relative to other tasks in the system,
|
||||||
|
* although the timers expiry time is relative to when resetFromISR() is
|
||||||
|
* actually called. The timer service/daemon task priority is set by the
|
||||||
|
* configTIMER_TASK_PRIORITY configuration constant.
|
||||||
|
* @return false If the change period command could not be sent to the timer
|
||||||
|
* command queue.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/resetFromISR.cpp
|
||||||
|
*/
|
||||||
|
inline bool resetFromISR(bool& higherPriorityTaskWoken) const {
|
||||||
|
BaseType_t taskWoken = pdFALSE;
|
||||||
|
bool result = (xTimerResetFromISR(handle, &taskWoken) == pdPASS);
|
||||||
|
if (taskWoken == pdTRUE) {
|
||||||
|
higherPriorityTaskWoken = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>BaseType_t xTimerResetFromISR( TimerHandle_t
|
||||||
|
* xTimer, BaseType_t *pxHigherPriorityTaskWoken )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerResetFromISR.html>
|
||||||
|
*
|
||||||
|
* @overload
|
||||||
|
*/
|
||||||
|
inline bool resetFromISR() const {
|
||||||
|
return (xTimerResetFromISR(handle, NULL) == pdPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>void vTimerSetReloadMode( TimerHandle_t
|
||||||
|
* xTimer, const UBaseType_t uxAutoReload )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-Timers-vTimerSetReloadMode.html>
|
||||||
|
*
|
||||||
|
* Updates the 'mode' of a software timer to be either an auto reload timer or
|
||||||
|
* a one-shot timer.
|
||||||
|
*
|
||||||
|
* An auto reload timer resets itself each time it expires, causing the timer
|
||||||
|
* to expire (and therefore execute its callback) periodically.
|
||||||
|
*
|
||||||
|
* A one shot timer does not automatically reset itself, so will only expire
|
||||||
|
* (and therefore execute its callback) once unless it is manually restarted.
|
||||||
|
*
|
||||||
|
* @param autoReload Set autoReload to true to set the timer into auto reload
|
||||||
|
* mode, or false to set the timer into one shot mode.
|
||||||
|
*/
|
||||||
|
inline void setReloadMode(const bool autoReload) const {
|
||||||
|
vTimerSetReloadMode(handle, (autoReload ? pdTRUE : pdFALSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>const char * pcTimerGetName( TimerHandle_t
|
||||||
|
* xTimer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-pcTimerGetName.html>
|
||||||
|
*
|
||||||
|
* Returns the human readable text name of a software timer.
|
||||||
|
*
|
||||||
|
* Text names are assigned to timers in the constructor.
|
||||||
|
*
|
||||||
|
* @return const char* A pointer to the text name of the timer as a standard
|
||||||
|
* NULL terminated C string.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/getName.cpp
|
||||||
|
*/
|
||||||
|
inline const char* getName() const { return pcTimerGetName(handle); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>TickType_t xTimerGetPeriod( TimerHandle_t
|
||||||
|
* xTimer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerGetPeriod.html>
|
||||||
|
*
|
||||||
|
* Returns the period of a software timer. The period is specified in ticks.
|
||||||
|
*
|
||||||
|
* The period of a timer is initially set using the period parameter of the
|
||||||
|
* constructor. It can then be changed using the changePeriod() and
|
||||||
|
* changePeriodFromISR() API functions.
|
||||||
|
*
|
||||||
|
* @return TickType_t The period of the timer, in ticks.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/getPeriod.cpp
|
||||||
|
*/
|
||||||
|
inline TickType_t getPeriod() const { return xTimerGetPeriod(handle); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>TickType_t xTimerGetExpiryTime(
|
||||||
|
* TimerHandle_t xTimer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerGetExpiryTime.html>
|
||||||
|
*
|
||||||
|
* Returns the time at which the software timer will expire, which is the time
|
||||||
|
* at which the timer's callback function will execute.
|
||||||
|
*
|
||||||
|
* If the value returned by getExpiryTime() is less than the current time then
|
||||||
|
* the timer will expire after the tick count has overflowed and wrapped back
|
||||||
|
* to 0. Overflows are handled in the RTOS implementation itself, so a timer's
|
||||||
|
* callback function will execute at the correct time whether it is before or
|
||||||
|
* after the tick count overflows.
|
||||||
|
*
|
||||||
|
* @return TickType_t If the timer is active, then the time at which the timer
|
||||||
|
* will next expire is returned (which may be after the current tick count has
|
||||||
|
* overflowed, see the notes above). If the timer is not active then the
|
||||||
|
* return value is undefined.
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/getExpiryTime.cpp
|
||||||
|
*/
|
||||||
|
inline TickType_t getExpiryTime() const {
|
||||||
|
return xTimerGetExpiryTime(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Function that calls <tt>UBaseType_t uxTimerGetReloadMode(
|
||||||
|
* TimerHandle_t xTimer )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/uxTimerGetReloadMode.html>
|
||||||
|
*
|
||||||
|
* Queries the 'mode' of the software timer.
|
||||||
|
*
|
||||||
|
* The mode can be either an auto-reloaded timer, which automatically resets
|
||||||
|
* itself each time it expires, or a one-shot timer, which will expire only
|
||||||
|
* once unless it is manually restarted.
|
||||||
|
*
|
||||||
|
* @return true If the timer is an auto-reload timer.
|
||||||
|
* @return false Otherwise.
|
||||||
|
*/
|
||||||
|
inline bool getReloadMode() const {
|
||||||
|
return (uxTimerGetReloadMode(handle) == pdTRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Set the delete block time. This value is used when the destructor
|
||||||
|
* calls deleteTimer().
|
||||||
|
*
|
||||||
|
* @param deleteBlockTime Delete block time to be set in ticks.
|
||||||
|
*/
|
||||||
|
inline void setDeleteBlockTime(const TickType_t deleteBlockTime = 0) {
|
||||||
|
this->deleteBlockTime = deleteBlockTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Set the delete block time. This value is used when the destructor
|
||||||
|
* calls deleteTimer().
|
||||||
|
*
|
||||||
|
* @return TickType_t Delete block time in ticks.
|
||||||
|
*/
|
||||||
|
inline TickType_t getDeleteBlockTime() const { return deleteBlockTime; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Abstraction function that acts as the entry point of the timer
|
||||||
|
* callback for the user.
|
||||||
|
*/
|
||||||
|
virtual void timerFunction() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new TimerBase object. This default constructor is
|
||||||
|
* deliberately private as this class is not intended to be instantiated or
|
||||||
|
* derived from by the user. Use FreeRTOS::Timer or FreeRTOS::StaticTimer as
|
||||||
|
* a base class for creating a task.
|
||||||
|
*
|
||||||
|
* @param deleteBlockTime Set the delete block time. This value is used when
|
||||||
|
* the destructor calls deleteTimer().
|
||||||
|
*/
|
||||||
|
explicit TimerBase(const TickType_t deleteBlockTime = 0)
|
||||||
|
: deleteBlockTime(deleteBlockTime) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Destroy the TimerBase object.
|
||||||
|
*
|
||||||
|
* @note This destructor will check that the timer is still valid and has not
|
||||||
|
* already been deleted by deleteTimer() before calling the function. If the
|
||||||
|
* timer is still valid the destructor will call deleteTimer() and block for
|
||||||
|
* up to the amount of time specified by deleteBlockTime.
|
||||||
|
*/
|
||||||
|
~TimerBase() {
|
||||||
|
if (isValid()) {
|
||||||
|
deleteTimer(getDeleteBlockTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TimerBase(TimerBase&&) noexcept = default;
|
||||||
|
TimerBase& operator=(TimerBase&&) noexcept = default;
|
||||||
|
|
||||||
|
TimerHandle_t handle = NULL;
|
||||||
|
TickType_t deleteBlockTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer Timer.hpp <FreeRTOS/Timer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS timer.
|
||||||
|
*
|
||||||
|
* Each software timer requires a small amount of RAM that is used to hold the
|
||||||
|
* timer's state. If a timer is created using this class then this RAM is
|
||||||
|
* automatically allocated from the FreeRTOS heap. If a software timer is
|
||||||
|
* created using FreeRTOS::StaticTimer() then the RAM is included in the object
|
||||||
|
* so it can be statically allocated at compile time. See the Static Vs Dynamic
|
||||||
|
* allocation page for more information.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. The user
|
||||||
|
* should create a class that derives from this class and implement
|
||||||
|
* timerFunction().
|
||||||
|
*/
|
||||||
|
class Timer : public TimerBase {
|
||||||
|
public:
|
||||||
|
Timer(const Timer&) = delete;
|
||||||
|
Timer& operator=(const Timer&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new Timer object by calling <tt>TimerHandle_t
|
||||||
|
* xTimerCreate( const char * const pcTimerName, const TickType_t
|
||||||
|
* xTimerPeriod, const UBaseType_t uxAutoReload, void * const pvTimerID,
|
||||||
|
* TimerCallbackFunction_t pxCallbackFunction )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/FreeRTOS-timers-xTimerCreate.html>
|
||||||
|
*
|
||||||
|
* @warning The user should call isValid() on this object to verify that the
|
||||||
|
* timer was created successfully in case the memory required to create the
|
||||||
|
* timer could not be allocated.
|
||||||
|
*
|
||||||
|
* @note Timers are created in the dormant state. The start(), reset(),
|
||||||
|
* startFromISR(), resetFromISR(), changePeriod() and changePeriodFromISR()
|
||||||
|
* API functions can all be used to transition a timer into the active state.
|
||||||
|
*
|
||||||
|
* @note When calling <tt>xTimerCreate</tt> the constructor passes the
|
||||||
|
* <tt>this</tt> pointer as the pvTimerID argument. This pointer is used so
|
||||||
|
* that the interface function callTimerFunction() can invoke timerFunction()
|
||||||
|
* for this instance of the class.
|
||||||
|
*
|
||||||
|
* @param period The period of the timer. The period is specified in ticks,
|
||||||
|
* and the macro pdMS_TO_TICKS() can be used to convert a time specified in
|
||||||
|
* milliseconds to a time specified in ticks. For example, if the timer must
|
||||||
|
* expire after 100 ticks, then simply set period to 100. Alternatively, if
|
||||||
|
* the timer must expire after 500ms, then set period to pdMS_TO_TICKS( 500 ).
|
||||||
|
* pdMS_TO_TICKS() can only be used if configTICK_RATE_HZ is less than or
|
||||||
|
* equal to 1000. The timer period must be greater than 0.
|
||||||
|
* @param autoReload If autoReload is set to true, then the timer will expire
|
||||||
|
* repeatedly with a frequency set by the period parameter. If autoReload is
|
||||||
|
* set to false, then the timer will be a one-shot and enter the dormant state
|
||||||
|
* after it expires.
|
||||||
|
* @param name A human readable text name that is assigned to the timer. This
|
||||||
|
* is done purely to assist debugging. The RTOS kernel itself only ever
|
||||||
|
* references a timer by its handle, and never by its name.
|
||||||
|
* @param deleteBlockTime Specifies the time, in ticks, that the calling task
|
||||||
|
* should be held in the Blocked state to wait for the delete command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when the destructor is called. deleteBlockTime is ignored if the
|
||||||
|
* destructor is called before the RTOS scheduler is started or if the timer
|
||||||
|
* has already been deleted by deleteTimer() before the destructor is called.
|
||||||
|
* This value can be updated by calling setDeleteBlockTime().
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/timer.cpp
|
||||||
|
*/
|
||||||
|
explicit Timer(const TickType_t period, const bool autoReload = false,
|
||||||
|
const char* name = "", const TickType_t deleteBlockTime = 0)
|
||||||
|
: TimerBase(deleteBlockTime) {
|
||||||
|
this->handle = xTimerCreate(name, period, (autoReload ? pdTRUE : pdFALSE),
|
||||||
|
this, callTimerFunction);
|
||||||
|
}
|
||||||
|
~Timer() = default;
|
||||||
|
|
||||||
|
Timer(Timer&&) noexcept = default;
|
||||||
|
Timer& operator=(Timer&&) noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timer Timer.hpp <FreeRTOS/Timer.hpp>
|
||||||
|
*
|
||||||
|
* @brief Class that encapsulates the functionality of a FreeRTOS timer.
|
||||||
|
*
|
||||||
|
* Each software timer requires a small amount of RAM that is used to hold the
|
||||||
|
* timer's state. If a timer is created using FreeRTOS::Timer() then this RAM is
|
||||||
|
* automatically allocated from the FreeRTOS heap. If a software timer is
|
||||||
|
* created this class then the RAM is included in the object so it can be
|
||||||
|
* statically allocated at compile time. See the Static Vs Dynamic allocation
|
||||||
|
* page for more information.
|
||||||
|
*
|
||||||
|
* @note This class is not intended to be instantiated by the user. The user
|
||||||
|
* should create a class that derives from this class and implement
|
||||||
|
* timerFunction().
|
||||||
|
*
|
||||||
|
* @warning This class contains the timer data structure, so any instance of
|
||||||
|
* this class or class derived from this class should be persistent (not
|
||||||
|
* declared on the stack of another function).
|
||||||
|
*/
|
||||||
|
class StaticTimer : public TimerBase {
|
||||||
|
public:
|
||||||
|
StaticTimer(const StaticTimer&) = delete;
|
||||||
|
StaticTimer& operator=(const StaticTimer&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Timer.hpp
|
||||||
|
*
|
||||||
|
* @brief Construct a new StaticTimer object by calling <tt>TimerHandle_t
|
||||||
|
* xTimerCreateStatic( const char * const pcTimerName, const TickType_t
|
||||||
|
* xTimerPeriod, const UBaseType_t uxAutoReload, void * const pvTimerID,
|
||||||
|
* TimerCallbackFunction_t pxCallbackFunction StaticTimer_t *pxTimerBuffer
|
||||||
|
* )</tt>
|
||||||
|
*
|
||||||
|
* @see <https://www.freertos.org/xTimerCreateStatic.html>
|
||||||
|
*
|
||||||
|
* @note When calling <tt>xTimerCreateStatic</tt> the constructor passes the
|
||||||
|
* <tt>this</tt> pointer as the pvTimerID argument. This pointer is used so
|
||||||
|
* that the interface function callTimerFunction() can invoke timerFunction()
|
||||||
|
* for this instance of the class.
|
||||||
|
*
|
||||||
|
* @note Timers are created in the dormant state. The start(), reset(),
|
||||||
|
* startFromISR(), resetFromISR(), changePeriod() and changePeriodFromISR()
|
||||||
|
* API functions can all be used to transition a timer into the active state.
|
||||||
|
*
|
||||||
|
* @param period The period of the timer. The period is specified in ticks,
|
||||||
|
* and the macro pdMS_TO_TICKS() can be used to convert a time specified in
|
||||||
|
* milliseconds to a time specified in ticks. For example, if the timer must
|
||||||
|
* expire after 100 ticks, then simply set period to 100. Alternatively, if
|
||||||
|
* the timer must expire after 500ms, then set period to pdMS_TO_TICKS( 500 ).
|
||||||
|
* pdMS_TO_TICKS() can only be used if configTICK_RATE_HZ is less than or
|
||||||
|
* equal to 1000. The timer period must be greater than 0.
|
||||||
|
* @param autoReload If autoReload is set to true, then the timer will expire
|
||||||
|
* repeatedly with a frequency set by the period parameter. If autoReload is
|
||||||
|
* set to false, then the timer will be a one-shot and enter the dormant state
|
||||||
|
* after it expires.
|
||||||
|
* @param name A human readable text name that is assigned to the timer. This
|
||||||
|
* is done purely to assist debugging. The RTOS kernel itself only ever
|
||||||
|
* references a timer by its handle, and never by its name.
|
||||||
|
* @param deleteBlockTime Specifies the time, in ticks, that the calling task
|
||||||
|
* should be held in the Blocked state to wait for the delete command to be
|
||||||
|
* successfully sent to the timer command queue, should the queue already be
|
||||||
|
* full when the destructor is called. deleteBlockTime is ignored if the
|
||||||
|
* destructor is called before the RTOS scheduler is started or if the timer
|
||||||
|
* has already been deleted by deleteTimer() before the destructor is called.
|
||||||
|
* This value can be updated by calling setDeleteBlockTime().
|
||||||
|
*
|
||||||
|
* <b>Example Usage</b>
|
||||||
|
* @include Timer/staticTimer.cpp
|
||||||
|
*/
|
||||||
|
explicit StaticTimer(const TickType_t period, const bool autoReload = false,
|
||||||
|
const char* name = "",
|
||||||
|
const TickType_t deleteBlockTime = 0)
|
||||||
|
: TimerBase(deleteBlockTime) {
|
||||||
|
this->handle =
|
||||||
|
xTimerCreateStatic(name, period, (autoReload ? pdTRUE : pdFALSE), this,
|
||||||
|
callTimerFunction, &staticTimer);
|
||||||
|
}
|
||||||
|
~StaticTimer() = default;
|
||||||
|
|
||||||
|
StaticTimer(StaticTimer&&) noexcept = default;
|
||||||
|
StaticTimer& operator=(StaticTimer&&) noexcept = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StaticTimer_t staticTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
|
} // namespace FreeRTOS
|
||||||
|
|
||||||
|
inline void callTimerFunction(TimerHandle_t timer) {
|
||||||
|
static_cast<FreeRTOS::TimerBase*>(pvTimerGetTimerID(timer))->timerEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FREERTOS_TIMER_HPP
|
||||||
Loading…
x
Reference in New Issue
Block a user