LCOV - code coverage report
Current view: top level - asyncFreeRtos/include/async - FreeRtosAdapter.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 95 95 100.0 %
Date: 2025-02-26 13:32:38 Functions: 16 16 100.0 %

          Line data    Source code
       1             : // Copyright 2024 Accenture.
       2             : 
       3             : /**
       4             :  * \ingroup async
       5             :  */
       6             : #ifndef GUARD_DB9C7111_F66E_4D50_B724_5DF992A19ED0
       7             : #define GUARD_DB9C7111_F66E_4D50_B724_5DF992A19ED0
       8             : 
       9             : #include "async/TaskContext.h"
      10             : #include "async/TaskInitializer.h"
      11             : 
      12             : #include <estd/array.h>
      13             : #include <estd/singleton.h>
      14             : 
      15             : namespace async
      16             : {
      17             : namespace internal
      18             : {
      19             : template<bool HasNestedInterrupts = (ASYNC_CONFIG_NESTED_INTERRUPTS != 0)>
      20          10 : class NestedInterruptLock : public LockType
      21             : {};
      22             : 
      23             : template<>
      24             : class NestedInterruptLock<false>
      25             : {};
      26             : 
      27             : template<size_t N, typename TaskConfig = ASYNC_TASK_CONFIG_TYPE>
      28             : class TaskConfigHolder
      29             : {
      30             : public:
      31             :     using TaskConfigType = TaskConfig;
      32             : 
      33             :     static void setTaskConfig(size_t taskIdx, TaskConfigType const& taskConfig);
      34             : 
      35             :     static TaskConfigType const* getTaskConfig(size_t taskIdx);
      36             : 
      37             : private:
      38             :     static ::estd::array<TaskConfigType, N> _taskConfigs;
      39             : };
      40             : 
      41             : template<size_t N>
      42             : class TaskConfigHolder<N, void>
      43             : {
      44             : public:
      45             :     struct TaskConfigType
      46             :     {};
      47             : 
      48             :     static void setTaskConfig(size_t taskIdx, TaskConfigType const& taskConfig);
      49             : 
      50             :     static TaskConfigType const* getTaskConfig(size_t taskIdx);
      51             : };
      52             : 
      53             : } // namespace internal
      54             : 
      55             : /**
      56             :  * Adapter class bridging FreeRTOS functionalities with the application's binding.
      57             :  *
      58             :  * The `FreeRtosAdapter` class serves as a centralized interface for managing tasks, timers,
      59             :  * and scheduling functionalities within a FreeRTOS environment. It utilizes the specified
      60             :  * `Binding` type to adapt and configure task-related components, such as `TaskContext`,
      61             :  * `TaskConfig`, and idle and timer tasks.
      62             :  *
      63             :  * \tparam Binding The binding type specifying application-specific configurations.
      64             :  */
      65             : template<class Binding>
      66             : class FreeRtosAdapter
      67             : {
      68             : public:
      69             :     static size_t const TASK_COUNT          = Binding::TASK_COUNT;
      70             :     static size_t const FREERTOS_TASK_COUNT = TASK_COUNT + 1U;
      71             :     static TickType_t const WAIT_EVENTS_TICK_COUNT
      72             :         = static_cast<TickType_t>(Binding::WAIT_EVENTS_TICK_COUNT);
      73             :     static ContextType const TASK_IDLE  = 0U;
      74             :     static ContextType const TASK_TIMER = static_cast<ContextType>(TASK_COUNT);
      75             : 
      76             :     using AdapterType = FreeRtosAdapter<Binding>;
      77             : 
      78             :     using TaskContextType  = TaskContext<AdapterType>;
      79             :     using TaskFunctionType = typename TaskContextType::TaskFunctionType;
      80             : 
      81             :     using TaskConfigsType = internal::TaskConfigHolder<FREERTOS_TASK_COUNT>;
      82             :     using TaskConfigType  = typename TaskConfigsType::TaskConfigType;
      83             : 
      84             :     template<size_t StackSize>
      85             :     using Stack           = internal::Stack<StackSize>;
      86             :     using TaskInitializer = internal::TaskInitializer<AdapterType>;
      87             : 
      88             :     template<size_t StackSize = 0U>
      89             :     using IdleTask = internal::IdleTask<AdapterType, StackSize>;
      90             :     template<size_t StackSize = 0U>
      91             :     using TimerTask = internal::TimerTask<AdapterType, StackSize>;
      92             :     template<ContextType Context, size_t StackSize = 0U>
      93             :     using Task = internal::Task<AdapterType, Context, StackSize>;
      94             : 
      95             :     /// Struct representing the stack usage for a specific task.
      96             :     struct StackUsage
      97             :     {
      98             :         StackUsage();
      99             : 
     100             :         uint32_t _stackSize;
     101             :         uint32_t _usedSize;
     102             :     };
     103             : 
     104             :     /**
     105             :      * Retrieves memory pointers for a FreeRTOS task.
     106             :      *
     107             :      * \tparam Context The task context.
     108             :      * \param ppxTaskTCBBuffer Pointer to the task control block buffer.
     109             :      * \param ppxTaskStackBuffer Pointer to the task stack buffer.
     110             :      * \param pulTaskStackSize Pointer to the task stack size.
     111             :      */
     112             :     template<ContextType Context>
     113             :     static void getTaskMemory(
     114             :         StaticTask_t** ppxTaskTCBBuffer,
     115             :         StackType_t** ppxTaskStackBuffer,
     116             :         uint32_t* pulTaskStackSize);
     117             : 
     118             :     static char const* getTaskName(size_t taskIdx);
     119             : 
     120             :     static TaskHandle_t getTaskHandle(size_t taskIdx);
     121             : 
     122             :     static TaskConfigType const* getTaskConfig(size_t taskIdx);
     123             : 
     124             :     static ContextType getCurrentTaskContext();
     125             : 
     126             :     static void init();
     127             : 
     128             :     /// Starts the FreeRTOS scheduler.
     129             :     static void run();
     130             : 
     131             :     static void runningHook();
     132             : 
     133             :     /**
     134             :      * Retrieves the stack usage for a specified task.
     135             :      *
     136             :      * \param taskIdx The index of the task.
     137             :      * \param stackUsage A reference to the StackUsage struct to populate.
     138             :      * \return True if stack usage information is successfully retrieved.
     139             :      */
     140             :     static bool getStackUsage(size_t taskIdx, StackUsage& stackUsage);
     141             : 
     142             :     static void callIdleTaskFunction();
     143             : 
     144             :     /**
     145             :      * Executes a specified runnable within a given context.
     146             :      *
     147             :      * \param context The task context.
     148             :      * \param runnable The runnable to execute.
     149             :      */
     150             :     static void execute(ContextType context, RunnableType& runnable);
     151             : 
     152             :     /**
     153             :      * Schedules a runnable to execute after a delay.
     154             :      *
     155             :      * \param context The task context.
     156             :      * \param runnable The runnable to schedule.
     157             :      * \param timeout The timeout associated with the runnable.
     158             :      * \param delay The delay before execution.
     159             :      * \param unit The time unit for the delay.
     160             :      */
     161             :     static void schedule(
     162             :         ContextType context,
     163             :         RunnableType& runnable,
     164             :         TimeoutType& timeout,
     165             :         uint32_t delay,
     166             :         TimeUnitType unit);
     167             : 
     168             :     /**
     169             :      * Schedules a runnable to execute at a fixed rate.
     170             :      *
     171             :      * \param context The task context.
     172             :      * \param runnable The runnable to schedule.
     173             :      * \param timeout The timeout associated with the runnable.
     174             :      * \param delay The delay before the first execution.
     175             :      * \param unit The time unit for the delay.
     176             :      */
     177             :     static void scheduleAtFixedRate(
     178             :         ContextType context,
     179             :         RunnableType& runnable,
     180             :         TimeoutType& timeout,
     181             :         uint32_t delay,
     182             :         TimeUnitType unit);
     183             : 
     184             :     /**
     185             :      * Cancels a scheduled runnable.
     186             :      *
     187             :      * \param timeout The timeout associated with the runnable to cancel.
     188             :      */
     189             :     static void cancel(TimeoutType& timeout);
     190             : 
     191             :     /// Notifies the system of an interrupt entry.
     192             :     static void enterIsr();
     193             : 
     194             :     /// Notifies the system of an interrupt exit.
     195             :     static void leaveIsr();
     196             : 
     197             :     /**
     198             :      * Exits the ISR without yielding control.
     199             :      * \return True if yielding is not required after ISR.
     200             :      */
     201             :     static bool leaveIsrNoYield();
     202             : 
     203             :     /// \return A pointer to the task woken by the ISR.
     204             :     static BaseType_t* getHigherPriorityTaskWoken();
     205             : 
     206             : private:
     207             :     friend struct internal::TaskInitializer<AdapterType>;
     208             : 
     209             :     static void initTask(TaskInitializer& initializer);
     210             : 
     211             :     static void TaskFunction(void* param);
     212             : 
     213             :     static TaskInitializer* _idleTaskInitializer;
     214             :     static TaskInitializer* _timerTaskInitializer;
     215             :     static ::estd::array<TaskContextType, TASK_COUNT> _taskContexts;
     216             :     static ::estd::array<uint32_t, FREERTOS_TASK_COUNT> _stackSizes;
     217             :     static char const* _timerTaskName;
     218             :     static BaseType_t _higherPriorityTaskWokenFlag;
     219             :     static BaseType_t* _higherPriorityTaskWoken;
     220             :     static uint8_t _nestedInterruptCount;
     221             : };
     222             : 
     223             : /**
     224             :  * Inline implementations.
     225             :  */
     226             : template<class Binding>
     227             : typename FreeRtosAdapter<Binding>::TaskInitializer* FreeRtosAdapter<Binding>::_idleTaskInitializer
     228             :     = nullptr;
     229             : template<class Binding>
     230             : typename FreeRtosAdapter<Binding>::TaskInitializer* FreeRtosAdapter<Binding>::_timerTaskInitializer
     231             :     = nullptr;
     232             : template<class Binding>
     233             : ::estd::
     234             :     array<typename FreeRtosAdapter<Binding>::TaskContextType, FreeRtosAdapter<Binding>::TASK_COUNT>
     235             :         FreeRtosAdapter<Binding>::_taskContexts;
     236             : template<class Binding>
     237             : ::estd::array<uint32_t, FreeRtosAdapter<Binding>::FREERTOS_TASK_COUNT>
     238             :     FreeRtosAdapter<Binding>::_stackSizes;
     239             : template<class Binding>
     240             : char const* FreeRtosAdapter<Binding>::_timerTaskName;
     241             : template<class Binding>
     242             : BaseType_t FreeRtosAdapter<Binding>::_higherPriorityTaskWokenFlag = 0;
     243             : template<class Binding>
     244             : BaseType_t* FreeRtosAdapter<Binding>::_higherPriorityTaskWoken = nullptr;
     245             : template<class Binding>
     246             : uint8_t FreeRtosAdapter<Binding>::_nestedInterruptCount = 0U;
     247             : 
     248             : template<class Binding>
     249             : template<ContextType Context>
     250           2 : void FreeRtosAdapter<Binding>::getTaskMemory(
     251             :     StaticTask_t** const ppxTaskTCBBuffer,
     252             :     StackType_t** const ppxTaskStackBuffer,
     253             :     uint32_t* const pulTaskStackSize)
     254             : {
     255           2 :     TaskInitializer& initializer
     256             :         = *((Context == TASK_IDLE) ? _idleTaskInitializer : _timerTaskInitializer);
     257           2 :     estd_assert(ppxTaskTCBBuffer != nullptr);
     258           2 :     estd_assert(ppxTaskStackBuffer != nullptr);
     259           2 :     estd_assert(pulTaskStackSize != nullptr);
     260           2 :     *ppxTaskTCBBuffer   = &initializer._task;
     261           2 :     *ppxTaskStackBuffer = initializer._stack.data();
     262             :     // Conversion to uint32_t is OK, stack will not exceed 4GB.
     263           2 :     *pulTaskStackSize   = static_cast<uint32_t>(initializer._stack.size());
     264           2 : }
     265             : 
     266             : template<class Binding>
     267           3 : inline char const* FreeRtosAdapter<Binding>::getTaskName(size_t const taskIdx)
     268             : {
     269           4 :     return (taskIdx < _taskContexts.size()) ? _taskContexts[taskIdx].getName() : _timerTaskName;
     270             : }
     271             : 
     272             : template<class Binding>
     273           1 : inline TaskHandle_t FreeRtosAdapter<Binding>::getTaskHandle(size_t const taskIdx)
     274             : {
     275           1 :     return _taskContexts[taskIdx].getTaskHandle();
     276             : }
     277             : 
     278             : template<class Binding>
     279             : inline typename FreeRtosAdapter<Binding>::TaskConfigType const*
     280           1 : FreeRtosAdapter<Binding>::getTaskConfig(size_t const taskIdx)
     281             : {
     282           1 :     return TaskConfigsType::getTaskConfig(taskIdx);
     283             : }
     284             : 
     285             : template<class Binding>
     286           7 : ContextType FreeRtosAdapter<Binding>::getCurrentTaskContext()
     287             : {
     288           7 :     if (_higherPriorityTaskWoken == nullptr)
     289             :     {
     290           6 :         return static_cast<ContextType>(uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle()));
     291             :     }
     292             :     return CONTEXT_INVALID;
     293             : }
     294             : 
     295             : template<class Binding>
     296           8 : void FreeRtosAdapter<Binding>::initTask(TaskInitializer& initializer)
     297             : {
     298           8 :     ContextType const context                 = initializer._context;
     299           8 :     _stackSizes[static_cast<size_t>(context)] = static_cast<uint32_t>(
     300           8 :         static_cast<size_t>(initializer._stack.size()) * sizeof(BaseType_t));
     301             :     TaskConfigsType::setTaskConfig(context, initializer._config);
     302           8 :     if (context == TASK_TIMER)
     303             :     {
     304           2 :         _timerTaskInitializer = &initializer;
     305           2 :         _timerTaskName        = initializer._name;
     306             :     }
     307             :     else
     308             :     {
     309           6 :         TaskContextType& taskContext = _taskContexts[static_cast<size_t>(context)];
     310           6 :         if (context == TASK_IDLE)
     311             :         {
     312           1 :             _idleTaskInitializer = &initializer;
     313           1 :             taskContext.initTask(TASK_IDLE, initializer._name, initializer._taskFunction);
     314             :         }
     315             :         else
     316             :         {
     317           5 :             taskContext.createTask(
     318             :                 context,
     319           5 :                 initializer._task,
     320             :                 initializer._name,
     321             :                 static_cast<UBaseType_t>(context),
     322           5 :                 initializer._stack,
     323             :                 initializer._taskFunction);
     324             :         }
     325             :     }
     326           8 : }
     327             : 
     328             : template<class Binding>
     329           7 : void FreeRtosAdapter<Binding>::init()
     330             : {
     331           7 :     TaskInitializer::run();
     332             : }
     333             : 
     334             : template<class Binding>
     335           1 : void FreeRtosAdapter<Binding>::run()
     336             : {
     337           1 :     vTaskStartScheduler();
     338             : }
     339             : 
     340             : template<class Binding>
     341           1 : void FreeRtosAdapter<Binding>::runningHook()
     342             : {
     343           1 :     _taskContexts[TASK_IDLE].initTaskHandle(xTaskGetIdleTaskHandle());
     344             : }
     345             : 
     346             : template<class Binding>
     347           2 : bool FreeRtosAdapter<Binding>::getStackUsage(size_t const taskIdx, StackUsage& stackUsage)
     348             : {
     349           2 :     if (taskIdx < FREERTOS_TASK_COUNT)
     350             :     {
     351           2 :         stackUsage._stackSize = _stackSizes[taskIdx];
     352           2 :         uint32_t const unusedSize
     353             :             = (taskIdx == TASK_TIMER)
     354           2 :                   ? TaskContextType::getUnusedStackSize(xTimerGetTimerDaemonTaskHandle())
     355           1 :                   : _taskContexts[taskIdx].getUnusedStackSize();
     356           2 :         stackUsage._usedSize = stackUsage._stackSize - unusedSize;
     357           2 :         return true;
     358             :     }
     359             :     return false;
     360             : }
     361             : 
     362             : template<class Binding>
     363           1 : inline void FreeRtosAdapter<Binding>::callIdleTaskFunction()
     364             : {
     365           1 :     _taskContexts[TASK_IDLE].callTaskFunction();
     366             : }
     367             : 
     368             : template<class Binding>
     369           2 : inline void FreeRtosAdapter<Binding>::execute(ContextType const context, RunnableType& runnable)
     370             : {
     371           2 :     _taskContexts[static_cast<size_t>(context)].execute(runnable);
     372             : }
     373             : 
     374             : template<class Binding>
     375           2 : inline void FreeRtosAdapter<Binding>::schedule(
     376             :     ContextType const context,
     377             :     RunnableType& runnable,
     378             :     TimeoutType& timeout,
     379             :     uint32_t const delay,
     380             :     TimeUnitType const unit)
     381             : {
     382           2 :     _taskContexts[static_cast<size_t>(context)].schedule(runnable, timeout, delay, unit);
     383             : }
     384             : 
     385             : template<class Binding>
     386           2 : inline void FreeRtosAdapter<Binding>::scheduleAtFixedRate(
     387             :     ContextType const context,
     388             :     RunnableType& runnable,
     389             :     TimeoutType& timeout,
     390             :     uint32_t const delay,
     391             :     TimeUnitType const unit)
     392             : {
     393           2 :     _taskContexts[static_cast<size_t>(context)].scheduleAtFixedRate(runnable, timeout, delay, unit);
     394             : }
     395             : 
     396             : template<class Binding>
     397           5 : inline void FreeRtosAdapter<Binding>::cancel(TimeoutType& timeout)
     398             : {
     399           5 :     LockType const lock;
     400           5 :     ContextType const context = timeout._context;
     401           5 :     if (context != CONTEXT_INVALID)
     402             :     {
     403           4 :         timeout._context = CONTEXT_INVALID;
     404           9 :         _taskContexts[static_cast<size_t>(context)].cancel(timeout);
     405             :     }
     406           5 : }
     407             : 
     408             : template<class Binding>
     409          32 : inline BaseType_t* FreeRtosAdapter<Binding>::getHigherPriorityTaskWoken()
     410             : {
     411          32 :     return _higherPriorityTaskWoken;
     412             : }
     413             : 
     414             : template<class Binding>
     415          10 : inline void FreeRtosAdapter<Binding>::enterIsr()
     416             : {
     417          10 :     internal::NestedInterruptLock<> const lock;
     418          10 :     ++_nestedInterruptCount;
     419          10 :     _higherPriorityTaskWoken = &FreeRtosAdapter::_higherPriorityTaskWokenFlag;
     420          10 : }
     421             : 
     422             : template<class Binding>
     423           5 : inline void FreeRtosAdapter<Binding>::leaveIsr()
     424             : {
     425           5 :     internal::NestedInterruptLock<> const lock;
     426           5 :     --_nestedInterruptCount;
     427           5 :     if (_nestedInterruptCount == 0U)
     428             :     {
     429           4 :         FreeRtosAdapter::_higherPriorityTaskWoken = nullptr;
     430           4 :         if (FreeRtosAdapter::_higherPriorityTaskWokenFlag != pdFALSE)
     431             :         {
     432           1 :             FreeRtosAdapter::_higherPriorityTaskWokenFlag = pdFALSE;
     433           1 :             portYIELD_FROM_ISR(pdTRUE);
     434             :         }
     435             :     }
     436           5 : }
     437             : 
     438             : template<class Binding>
     439           5 : inline bool FreeRtosAdapter<Binding>::leaveIsrNoYield()
     440             : {
     441           5 :     internal::NestedInterruptLock<> const lock;
     442           5 :     --_nestedInterruptCount;
     443           5 :     if (_nestedInterruptCount == 0U)
     444             :     {
     445           4 :         FreeRtosAdapter::_higherPriorityTaskWoken = nullptr;
     446           4 :         if (FreeRtosAdapter::_higherPriorityTaskWokenFlag != pdFALSE)
     447             :         {
     448           2 :             FreeRtosAdapter::_higherPriorityTaskWokenFlag = pdFALSE;
     449           2 :             return true;
     450             :         }
     451             :     }
     452             :     return false;
     453           5 : }
     454             : 
     455             : template<class Binding>
     456           1 : FreeRtosAdapter<Binding>::StackUsage::StackUsage() : _stackSize(0U), _usedSize(0U)
     457             : {}
     458             : 
     459             : namespace internal
     460             : {
     461             : template<size_t N, typename TaskConfig>
     462             : ::estd::array<TaskConfig, N> TaskConfigHolder<N, TaskConfig>::_taskConfigs;
     463             : 
     464             : template<size_t N, typename TaskConfig>
     465           1 : void TaskConfigHolder<N, TaskConfig>::setTaskConfig(
     466             :     size_t const taskIdx, TaskConfigType const& taskConfig)
     467             : {
     468           1 :     _taskConfigs[taskIdx] = taskConfig;
     469             : }
     470             : 
     471             : template<size_t N, typename TaskConfig>
     472           1 : TaskConfig const* TaskConfigHolder<N, TaskConfig>::getTaskConfig(size_t const taskIdx)
     473             : {
     474           1 :     return &_taskConfigs[taskIdx];
     475             : }
     476             : 
     477             : template<size_t N>
     478             : void TaskConfigHolder<N, void>::setTaskConfig(
     479             :     size_t const /*taskIdx*/,
     480             :     typename TaskConfigHolder<N, void>::TaskConfigType const& /*taskConfig*/)
     481             : {}
     482             : 
     483             : template<size_t N>
     484             : typename TaskConfigHolder<N, void>::TaskConfigType const*
     485           1 : TaskConfigHolder<N, void>::getTaskConfig(size_t const /*taskIdx*/)
     486             : {
     487           1 :     estd_assert(false);
     488             :     return nullptr;
     489             : }
     490             : 
     491             : } // namespace internal
     492             : 
     493             : } // namespace async
     494             : 
     495             : #endif // GUARD_DB9C7111_F66E_4D50_B724_5DF992A19ED0

Generated by: LCOV version 1.14