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