Line data Source code
1 : // Copyright 2024 Accenture.
2 :
3 : #pragma once
4 :
5 : #include "async/StaticRunnable.h"
6 : #include "async/Types.h"
7 : #include "estd/array.h"
8 : #include "estd/assert.h"
9 : #include "estd/memory.h"
10 : #include "estd/slice.h"
11 :
12 : #include <FreeRTOS.h>
13 : #include <task.h>
14 : #include <timers.h>
15 :
16 : namespace async
17 : {
18 : namespace internal
19 : {
20 :
21 : constexpr size_t adjustStackSize(size_t const stackSize)
22 : {
23 : #if (defined(MINIMUM_STACK_SIZE)) && (MINIMUM_STACK_SIZE != 0)
24 : return (stackSize != 0U) && (stackSize < MINIMUM_STACK_SIZE) ? MINIMUM_STACK_SIZE : stackSize;
25 : #else
26 : return stackSize;
27 : #endif // (defined(MINIMUM_STACK_SIZE)) && (MINIMUM_STACK_SIZE != 0)
28 : }
29 :
30 : template<size_t StackSize>
31 : using Stack = ::estd::array<
32 : StackType_t,
33 : (adjustStackSize(StackSize) + sizeof(StackType_t) - 1) / sizeof(StackType_t)>;
34 :
35 : /**
36 : * The TaskInitializer struct centralizes the initialization of tasks within the application.
37 : *
38 : * This struct provides a standardized way to set up tasks, defining key types and handling
39 : * configuration and setup of task and timer objects. It uses a specified Adapter type
40 : * for flexibility, allowing for different configurations.
41 : *
42 : * \tparam Adapter The adapter type used to provide specific task configuration types and functions.
43 : */
44 : template<typename Adapter>
45 : struct TaskInitializer : public StaticRunnable<TaskInitializer<Adapter>>
46 : {
47 : using AdapterType = Adapter;
48 : using StackSliceType = ::estd::slice<StackType_t>;
49 : using TaskConfigType = typename AdapterType::TaskConfigType;
50 : using TaskFunctionType = typename AdapterType::TaskFunctionType;
51 : using TaskObjectType = StaticTask_t;
52 :
53 : /**
54 : * Creates and initializes a task with the specified parameters.
55 : *
56 : * This function handles task creation by allocating memory for the object,
57 : * setting up the context, stack, and configuration,
58 : * and linking them to the specified task and timer objects.
59 : *
60 : * \tparam T The type of the stack used by the task.
61 : * \param context The execution context of the task.
62 : * \param name The name of the task.
63 : * \param task The static task object to initialize.
64 : * \param timer The static timer object associated with the task.
65 : * \param stack The stack to use for the task's execution.
66 : * \param taskFunction The function that the task will execute.
67 : * \param config Configuration settings for the task.
68 : */
69 : template<typename T>
70 : static void create(
71 : ContextType context,
72 : char const* name,
73 : TaskObjectType& task,
74 : T& stack,
75 : TaskFunctionType taskFunction,
76 : TaskConfigType const& config);
77 :
78 : private:
79 : TaskInitializer(
80 : ContextType context,
81 : char const* name,
82 : TaskObjectType& task,
83 : StackSliceType const& stack,
84 : TaskFunctionType taskFunction,
85 : TaskConfigType const& config);
86 :
87 : public:
88 : /// Executes task object initialization.
89 : void execute();
90 :
91 : /// The stack slice used for task execution.
92 : StackSliceType _stack;
93 :
94 : /// The function assigned for the task's execution.
95 : TaskFunctionType _taskFunction;
96 :
97 : /// Reference to the static task object.
98 : TaskObjectType& _task;
99 : /// The name of the task.
100 : char const* _name;
101 :
102 : /// The context in which the task will execute.
103 : ContextType _context;
104 :
105 : /// The configuration settings for the task.
106 : TaskConfigType _config;
107 : };
108 :
109 : /**
110 : * Primary template class that serves as a container for task-related objects and
111 : * configuration.
112 : *
113 : * TaskImpl provides a structure to hold essential components for tasks, such as the stack, task
114 : * object, and timer object, along with configuration settings. It serves as a base for derived task
115 : * classes (e.g., Task, IdleTask) and is designed for integration with FreeRTOS, using the Adapter
116 : * type for flexibility.
117 : *
118 : * \tparam Adapter The adapter type that supplies specific task configuration types and functions.
119 : * \tparam Context The context in which the task operates.
120 : * \tparam StackSize The size of the stack allocated for the task.
121 : */
122 : template<class Adapter, ContextType Context, size_t StackSize = 0U>
123 : class TaskImpl
124 : {
125 : public:
126 : using AdapterType = Adapter;
127 : using StackSliceType = ::estd::slice<StackType_t>;
128 : using TaskConfigType = typename AdapterType::TaskConfigType;
129 : using TaskFunctionType = typename AdapterType::TaskFunctionType;
130 : using TaskObjectType = StaticTask_t;
131 :
132 : TaskImpl(char const* name, TaskFunctionType taskFunction, TaskConfigType const& taskConfig);
133 :
134 : protected:
135 : ~TaskImpl() = default;
136 :
137 : private:
138 : Stack<StackSize> _stack;
139 : TaskObjectType _task;
140 : };
141 :
142 : template<class Adapter, ContextType Context>
143 : class TaskImpl<Adapter, Context, 0U>
144 : {
145 : public:
146 : using AdapterType = Adapter;
147 : using StackSliceType = ::estd::slice<StackType_t>;
148 : using TaskConfigType = typename AdapterType::TaskConfigType;
149 : using TaskFunctionType = typename AdapterType::TaskFunctionType;
150 : using TaskObjectType = StaticTask_t;
151 :
152 : template<typename T>
153 : TaskImpl(
154 : char const* name,
155 : T& stack,
156 : TaskFunctionType taskFunction,
157 : TaskConfigType const& taskConfig);
158 :
159 : protected:
160 : ~TaskImpl() = default;
161 :
162 : private:
163 : TaskObjectType _task;
164 : };
165 :
166 : template<class Adapter, size_t StackSize = 0U>
167 : struct IdleTask : public TaskImpl<Adapter, Adapter::TASK_IDLE, StackSize>
168 : {
169 : using TaskFunctionType = typename Adapter::TaskFunctionType;
170 : using TaskConfigType = typename Adapter::TaskConfigType;
171 :
172 : IdleTask(
173 : char const* name,
174 : TaskFunctionType taskFunction,
175 : TaskConfigType const& taskConfig = TaskConfigType());
176 : };
177 :
178 : template<class Adapter>
179 : struct IdleTask<Adapter, 0U> : public TaskImpl<Adapter, Adapter::TASK_IDLE>
180 : {
181 : using TaskFunctionType = typename Adapter::TaskFunctionType;
182 : using TaskConfigType = typename Adapter::TaskConfigType;
183 :
184 : template<typename T>
185 : IdleTask(
186 : char const* name,
187 : T& stack,
188 : TaskFunctionType taskFunction,
189 : TaskConfigType const& taskConfig = TaskConfigType());
190 : };
191 :
192 : template<class Adapter, size_t StackSize = 0U>
193 : struct TimerTask : public TaskImpl<Adapter, Adapter::TASK_TIMER, StackSize>
194 : {
195 : using TaskConfigType = typename Adapter::TaskConfigType;
196 :
197 : explicit TimerTask(char const* name, TaskConfigType const& taskConfig = TaskConfigType());
198 : };
199 :
200 : template<class Adapter>
201 : struct TimerTask<Adapter, 0U> : public TaskImpl<Adapter, Adapter::TASK_TIMER>
202 : {
203 : using TaskConfigType = typename Adapter::TaskConfigType;
204 :
205 : template<typename T>
206 : TimerTask(char const* name, T& stack, TaskConfigType const& taskConfig = TaskConfigType());
207 : };
208 :
209 : template<class Adapter, ContextType Context, size_t StackSize = 0U>
210 : struct Task : public TaskImpl<Adapter, Context, StackSize>
211 : {
212 : using TaskFunctionType = typename Adapter::TaskFunctionType;
213 : using TaskConfigType = typename Adapter::TaskConfigType;
214 :
215 : explicit Task(char const* name, TaskConfigType const& taskConfig = TaskConfigType());
216 :
217 : Task(
218 : char const* name,
219 : TaskFunctionType taskFunction,
220 : TaskConfigType const& taskConfig = TaskConfigType());
221 : };
222 :
223 : template<class Adapter, ContextType Context>
224 : struct Task<Adapter, Context, 0U> : public TaskImpl<Adapter, Context>
225 : {
226 : using TaskFunctionType = typename Adapter::TaskFunctionType;
227 : using TaskConfigType = typename Adapter::TaskConfigType;
228 :
229 : template<typename T>
230 : explicit Task(char const* name, T& stack, TaskConfigType const& taskConfig = TaskConfigType());
231 :
232 : template<typename T>
233 : Task(
234 : char const* name,
235 : T& stack,
236 : TaskFunctionType taskFunction,
237 : TaskConfigType const& taskConfig = TaskConfigType());
238 : };
239 :
240 : template<class Adapter>
241 : template<typename T>
242 17 : void TaskInitializer<Adapter>::create(
243 : ContextType const context,
244 : char const* const name,
245 : TaskObjectType& task,
246 : T& stack,
247 : TaskFunctionType const taskFunction,
248 : TaskConfigType const& config)
249 : {
250 17 : ::estd::slice<uint8_t> bytes = ::estd::make_slice(stack).template reinterpret_as<uint8_t>();
251 17 : ::estd::memory::align(alignof(StackType_t), bytes);
252 17 : StackSliceType const stackSlice = bytes.template reinterpret_as<StackType_t>();
253 17 : estd_assert((stackSlice.size() * sizeof(StackType_t)) >= sizeof(TaskInitializer));
254 16 : new (stackSlice.data()) TaskInitializer(context, name, task, stackSlice, taskFunction, config);
255 16 : }
256 :
257 : template<class Adapter>
258 16 : TaskInitializer<Adapter>::TaskInitializer(
259 : ContextType const context,
260 : char const* const name,
261 : TaskObjectType& task,
262 : StackSliceType const& stack,
263 : TaskFunctionType const taskFunction,
264 : TaskConfigType const& config)
265 16 : : _stack(stack)
266 16 : , _taskFunction(taskFunction)
267 16 : , _task(task)
268 16 : , _name(name)
269 16 : , _context(context)
270 16 : , _config(config)
271 : {}
272 :
273 : template<class Adapter>
274 16 : void TaskInitializer<Adapter>::execute()
275 : {
276 16 : Adapter::initTask(*this);
277 16 : }
278 :
279 : template<class Adapter, ContextType Context, size_t StackSize>
280 13 : TaskImpl<Adapter, Context, StackSize>::TaskImpl(
281 : char const* const name, TaskFunctionType const taskFunction, TaskConfigType const& taskConfig)
282 : {
283 7 : TaskInitializer<Adapter>::create(Context, name, _task, _stack, taskFunction, taskConfig);
284 : }
285 :
286 : template<class Adapter, ContextType Context>
287 : template<typename T>
288 4 : TaskImpl<Adapter, Context, 0U>::TaskImpl(
289 : char const* const name,
290 : T& stack,
291 : TaskFunctionType const taskFunction,
292 : TaskConfigType const& taskConfig)
293 : {
294 2 : TaskInitializer<Adapter>::create(Context, name, _task, stack, taskFunction, taskConfig);
295 : }
296 :
297 : template<class Adapter, size_t StackSize>
298 2 : IdleTask<Adapter, StackSize>::IdleTask(
299 : char const* const name, TaskFunctionType const taskFunction, TaskConfigType const& taskConfig)
300 2 : : TaskImpl<Adapter, Adapter::TASK_IDLE, StackSize>(name, taskFunction, taskConfig)
301 2 : {}
302 :
303 : template<class Adapter>
304 : template<typename T>
305 1 : IdleTask<Adapter, 0U>::IdleTask(
306 : char const* const name,
307 : T& stack,
308 : TaskFunctionType const taskFunction,
309 : TaskConfigType const& taskConfig)
310 1 : : TaskImpl<Adapter, Adapter::TASK_IDLE>(name, stack, taskFunction, taskConfig)
311 : {}
312 :
313 : template<class Adapter, size_t StackSize>
314 2 : TimerTask<Adapter, StackSize>::TimerTask(char const* const name, TaskConfigType const& taskConfig)
315 : : TaskImpl<Adapter, Adapter::TASK_TIMER, StackSize>(
316 2 : name, typename Adapter::TaskFunctionType(), taskConfig)
317 2 : {}
318 :
319 : template<class Adapter>
320 : template<typename T>
321 1 : TimerTask<Adapter, 0U>::TimerTask(
322 : char const* const name, T& stack, TaskConfigType const& taskConfig)
323 : : TaskImpl<Adapter, Adapter::TASK_TIMER>(
324 1 : name, stack, typename Adapter::TaskFunctionType(), taskConfig)
325 1 : {}
326 :
327 : template<class Adapter, ContextType Context, size_t StackSize>
328 5 : Task<Adapter, Context, StackSize>::Task(char const* const name, TaskConfigType const& taskConfig)
329 5 : : TaskImpl<Adapter, Context, StackSize>(name, TaskFunctionType(), taskConfig)
330 4 : {}
331 :
332 : template<class Adapter, ContextType Context, size_t StackSize>
333 4 : Task<Adapter, Context, StackSize>::Task(
334 : char const* const name, TaskFunctionType const taskFunction, TaskConfigType const& taskConfig)
335 4 : : TaskImpl<Adapter, Context, StackSize>(name, taskFunction, taskConfig)
336 4 : {}
337 :
338 : template<class Adapter, ContextType Context>
339 : template<typename T>
340 1 : Task<Adapter, Context, 0U>::Task(char const* const name, T& stack, TaskConfigType const& taskConfig)
341 1 : : TaskImpl<Adapter, Context>(name, stack, typename Adapter::TaskFunctionType(), taskConfig)
342 1 : {}
343 :
344 : template<class Adapter, ContextType Context>
345 : template<typename T>
346 1 : Task<Adapter, Context, 0U>::Task(
347 : char const* const name,
348 : T& stack,
349 : TaskFunctionType const taskFunction,
350 : TaskConfigType const& taskConfig)
351 1 : : TaskImpl<Adapter, Context>(name, stack, taskFunction, taskConfig)
352 : {}
353 :
354 : } // namespace internal
355 : } // namespace async
|