TaskManagerIO
Loading...
Searching...
No Matches
TaskPlatformDeps.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 https://www.thecoderscorner.com (Dave Cherry)..
3 * This product is licensed under an Apache license, see the LICENSE file in the top-level directory.
4 */
5
6
7#ifndef TASKMANAGERIO_PLATFORMDETERMINATION_H
8#define TASKMANAGERIO_PLATFORMDETERMINATION_H
9
14
15class TimerTask;
16
17// You can add your own local definitions header file here, this enables you to adjust build flags in environments
18// where there is no easy way to do so with compiler options. Just create an include file "io_local_definitions.h"
19// at the top level of your project source tree. This file will be honoured by all our libraries.
20#if defined __has_include
21# if __has_include ("zio_local_definitions.h")
22# include "zio_local_definitions.h"
23# endif
24#endif // has include "io_local_definitions"
25
26// when not on mbed, we need to load Arduino.h to get the right defines for some boards.
27#if defined(BUILD_FOR_PICO_CMAKE)
28#include <pico/stdlib.h>
29#include <valarray>
30#elif !defined(__MBED__)
31#include <Arduino.h>
32#endif
33
34#if defined(__MBED__) && !defined(ARDUINO_PICO_REVISION)
35
36#if defined(TM_ENABLE_CAPTURED_LAMBDAS)
37#define TM_ALLOW_CAPTURED_LAMBDA
38#endif
39
40// check if this is Arduino mbed or regular mbed.
41// list of devices is pulled from https://github.com/arduino/ArduinoCore-mbed/blob/master/full.variables
42// set TMIOA_FORCE_ARDUINO_MBED to force IoAbstraction to use Arduino-mbed mode.
43#if defined(ARDUINO_NANO_RP2040_CONNECT) || \
44 defined(ARDUINO_ARDUINO_NANO33BLE) || \
45 defined(ARDUINO_RASPBERRY_PI_PICO) || \
46 defined(ARDUINO_PORTENTA_H7_M7) || \
47 defined(ARDUINO_PORTENTA_H7_M4) || \
48 defined(ARDUINO_EDGE_CONTROL) || \
49 defined(ARDUINO_NICLA) || \
50 defined(ARDUINO_NICLA_VISION) || \
51 defined(TMIOA_FORCE_ARDUINO_MBED) || \
52 defined(ARDUINO_ARCH_MBED)
53# define IOA_USE_ARDUINO
54# define ARDUINO_MBED_MODE
55# include "Arduino.h"
56# define IOA_MULTITHREADED
57#include "rtos/rtos.h"
58inline void* getCurrentThreadId() { return rtos::ThisThread::get_id(); }
59#else
60# define IOA_USE_MBED
61# include "mbed.h"
62# define IOA_MULTITHREADED
63inline void* getCurrentThreadId() { return ThisThread::get_id(); }
64
65# if !defined(PIO_NEEDS_RTOS_WORKAROUND)
66# include "rtos.h"
67# endif // PIO_NEED_RTOS_WORKAROUND
68#endif // mbed and arduino-mbed checks
69
70#include <mbed_atomic.h>
71typedef uint32_t pintype_t;
72
73namespace tm_internal {
74 typedef TimerTask* volatile TimerTaskAtomicPtr;
75 typedef volatile bool TmAtomicBool;
76
84 inline bool atomicSwapBool(volatile bool *ptr, bool expected, bool newValue) {
85 return core_util_atomic_cas_bool(ptr, &expected, newValue);
86 }
87
91 inline bool atomicReadBool(TmAtomicBool *pPtr) {
92 return *pPtr;
93 }
94
95 inline void atomicWriteBool(TmAtomicBool *pPtr, bool newVal) {
96 *pPtr = newVal;
97 }
98
106 inline TimerTask *atomicReadPtr(TimerTaskAtomicPtr *pPtr) {
107 return *pPtr;
108 }
109
116 inline void atomicWritePtr(TimerTaskAtomicPtr *pPtr, TimerTask * volatile newValue) {
117 //core_util_atomic_store_ptr((void* volatile*)pPtr, newValue);
118 *pPtr = newValue;
119 }
120}
121#elif defined(ESP8266) || defined(ESP32) || defined(ARDUINO_PICO_REVISION)
122typedef uint8_t pintype_t;
123# define IOA_USE_ARDUINO
124#if defined(TM_ENABLE_CAPTURED_LAMBDAS)
125# define TM_ALLOW_CAPTURED_LAMBDA
126#endif
127
128#if defined(ESP8266) || defined(ARDUINO_PICO_REVISION)
129#include <atomic>
130namespace tm_internal {
131
132 typedef std::atomic<TimerTask *> TimerTaskAtomicPtr;
133
134 typedef std::atomic<uint32_t> TmAtomicBool;
135
143 inline bool atomicSwapBool(TmAtomicBool *ptr, bool expected, bool newValue) {
144 // compare and swap is not implemented on ESP8266
145 auto ret = false;
146 noInterrupts();
147 if(ptr->load() == expected) {
148 ptr->store(newValue);
149 ret = true;
150 }
151 interrupts();
152 return ret;
153 }
154
160 inline bool atomicReadBool(TmAtomicBool *pPtr) {
161 return pPtr->load();
162 }
163
169 inline void atomicWriteBool(TmAtomicBool *pPtr, bool newVal) {
170 pPtr->store(newVal);
171 }
172
180 inline TimerTask *atomicReadPtr(TimerTaskAtomicPtr *pPtr) {
181 return pPtr->load();
182 }
183
190 inline void atomicWritePtr(TimerTaskAtomicPtr *pPtr, TimerTask *newValue) {
191 pPtr->store(newValue);
192 }
193}
194#else
195# define IOA_MULTITHREADED
196inline void* getCurrentThreadId() { return xTaskGetCurrentTaskHandle() ; }
197
198namespace tm_internal {
199
200 typedef TimerTask* volatile TimerTaskAtomicPtr;
201 typedef volatile uint32_t TmAtomicBool; // to use CAS, the bool must be 32 bits wide
202
203
204// `uxPortCompareSet` was removed in ESP-IDF v5.0
205// See https://github.com/TcMenu/TaskManagerIO/issues/59
206#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
207 inline bool atomicSwapBool(TmAtomicBool *ptr, bool expected, bool newValue) {
208 uint32_t exp32 = expected;
209 uint32_t new32 = newValue;
210 uxPortCompareSet(ptr, exp32, &new32);
211 return new32 == expected;
212 }
213#else
214 inline bool atomicSwapBool(TmAtomicBool *ptr, bool expected, bool newValue) {
215 // function added in ESP-IDF v5.0
216 return esp_cpu_compare_and_set(ptr, expected, newValue);
217 }
218#endif
219
225 inline bool atomicReadBool(TmAtomicBool *pPtr) {
226 return *pPtr != 0;
227 }
228
234 inline void atomicWriteBool(TmAtomicBool *pPtr, bool newVal) {
235 *pPtr = newVal;
236 }
237
245 inline TimerTask *atomicReadPtr(TimerTaskAtomicPtr *pPtr) {
246 return *pPtr;
247 }
248
255 inline void atomicWritePtr(TimerTaskAtomicPtr *pPtr, TimerTask *newValue) {
256 *pPtr = newValue;
257 }
258}
259#endif
260#elif defined(BUILD_FOR_PICO_CMAKE)
261#include <pico/critical_section.h>
262#if defined(TM_ENABLE_CAPTURED_LAMBDAS)
263#define TM_ALLOW_CAPTURED_LAMBDA
264#endif
265typedef uint8_t pintype_t;
266namespace tm_internal {
267 typedef TimerTask *volatile TimerTaskAtomicPtr;
268 typedef volatile bool TmAtomicBool;
269 extern critical_section_t* tmLock;
270 void initPicoTmLock();
271
272 static bool atomicSwapBool(volatile bool *ptr, bool expected, bool newValue) {
273 bool ret = false;
274 critical_section_enter_blocking(tmLock);
275 if(*ptr == expected) {
276 *ptr = newValue;
277 ret = true;
278 }
279 critical_section_exit(tmLock);
280 return ret;
281 }
282
283 static void atomicWriteBool(volatile bool *ptr, bool val) {
284 critical_section_enter_blocking(tmLock);
285 *ptr = val;
286 critical_section_exit(tmLock);
287 }
288
289 inline bool atomicReadBool(volatile bool *ptr) {
290 bool ret = false;
291 critical_section_enter_blocking(tmLock);
292 ret = *ptr;
293 critical_section_exit(tmLock);
294 return ret;
295 }
296
297 inline void atomicWritePtr(TimerTaskAtomicPtr *ptr, TimerTask *newVal) {
298 *ptr = newVal;
299 }
300
301 inline TimerTask *atomicReadPtr(TimerTaskAtomicPtr *ptr) {
302 return *ptr;
303 }
304}
305#else
306// fall back to using Arduino regular logic, works for all single core boards. If we end up here for a multicore
307// board then there may be problems. Here we are in full arduino mode (AVR, MKR etc).
308# define IOA_USE_ARDUINO
309#include <Arduino.h>
310typedef uint8_t pintype_t;
311
312namespace tm_internal {
313typedef TimerTask *volatile TimerTaskAtomicPtr;
314typedef volatile bool TmAtomicBool;
315
316 static bool atomicSwapBool(volatile bool* ptr, bool expected, bool newValue) {
317 bool ret = false;
318 noInterrupts();
319 if(*ptr == expected) {
320 *ptr = newValue;
321 ret = true;
322 }
323 interrupts();
324 return ret;
325 }
326
327 inline bool atomicReadBool(volatile bool *ptr) {
328 return *ptr;
329 }
330
331 inline void atomicWriteBool(volatile bool *ptr, bool newVal) {
332 *ptr = newVal;
333 }
334
335#if defined(__AVR__)
336 inline void atomicWritePtr(TimerTaskAtomicPtr* pPtr, TimerTask* newValue) {
337 noInterrupts();
338 *pPtr = newValue;
339 interrupts();
340 }
341
342 inline TimerTask* atomicReadPtr(TimerTaskAtomicPtr* pPtr) {
343 noInterrupts();
344 auto ptr = *pPtr;
345 interrupts();
346 return ptr;
347 }
348#else
349// all other supported Arduino boards are atomic for pointer types
350inline void atomicWritePtr(TimerTaskAtomicPtr* pPtr, TimerTask* newValue) {
351 *pPtr = newValue;
352 }
353
354 inline TimerTask* atomicReadPtr(TimerTaskAtomicPtr* pPtr) {
355 return *pPtr;
356 }
357#endif // AVR check for PTR atomicity
358}
359#endif // All platform checks
360
361// for all mbed and ESP boards we already enable lambda captures, SAMD is a known extra case that works.
362// we can only enable on larger boards with enough memory to take the extra size of the structures.
363#if defined(TM_ENABLE_CAPTURED_LAMBDAS) && defined(ARDUINO_ARCH_SAMD)
364# define TM_ALLOW_CAPTURED_LAMBDA
365#endif
366
367//
368// Scheduling size. On all boards by default task manager uses 32 bit schedule data to make it more general purpose.
369// Note that even on 8 bit boards, all the math still needs to be 32 bit to deal with times, so there is very little
370// to no performance gain by doing this.
371//
372// If you need the few extra bytes back, and can live with 16 bit schedule values then define TM_FORCE_16BIT_SCHEDULER
373//
374#if defined(TM_FORCE_16BIT_SCHEDULER)
375typedef uint16_t sched_t;
376#else
377typedef uint32_t sched_t;
378#endif // TM_FORCE_16BIT_SCHEDULER
379
380//
381// DEFAULT_TASK_SIZE definition:
382// TaskManagerIO will re-allocate the task array if needed. So there's little need to adjust this for most use cases.
383// For AVR boards: MEGA 2560 has a default size of 10, others have a default size of 6.
384// For all other boards the default size is 16. You can change it by defining DEFAULT_TASK_SIZE yourself.
385//
386#ifndef DEFAULT_TASK_SIZE
387#ifdef __AVR_ATmega2560__
388# define DEFAULT_TASK_SIZE 12
389# define DEFAULT_TASK_BLOCKS 8
390#elif defined(__AVR__)
391# define DEFAULT_TASK_SIZE 6
392# define DEFAULT_TASK_BLOCKS 4
393#else
394# define DEFAULT_TASK_SIZE 16
395# define DEFAULT_TASK_BLOCKS 16
396#endif // platform
397#else
398#ifndef DEFAULT_TASK_BLOCKS
399#define DEFAULT_TASK_BLOCKS 8
400#endif // DEFAULT_TASK_BLOCKS not defined when task size is
401#endif // DEFAULT_TASK_SIZE defined already
402
403//
404// Here we define an attribute needed for interrupt support on ESP8266 and ESP32 boards, any interrupt code that is
405// going to run on these boards should be marked with this attribute.
406//
407#undef ISR_ATTR
408#if defined(ESP8266) || defined(ESP32)
409# define ISR_ATTR IRAM_ATTR
410#else
411# define ISR_ATTR
412#endif
413
414//
415// Here we have one last go at determining if we should enable capture lambdas by checking if the functional include
416// is available, we only do so if we are on GCC > 5
417//
418# if !defined(TM_ALLOW_CAPTURED_LAMBDA) && defined(TM_ENABLE_CAPTURED_LAMBDAS) && __GNUC__ >= 5
419#if __has_include(<functional>)
420# define TM_ALLOW_CAPTURED_LAMBDA
421#endif // _has_include
422#endif // GCC>=5 and !TM_ALLOW_CAPTURED_LAMBDA
423
424#ifndef internal_min
425#define internal_min(a, b) ((a) > (b) ? (b) : (a))
426#endif // internal_min
427
428#ifndef internal_max
429#define internal_max(a, b) ((a) < (b) ? (b) : (a));
430#endif // internal_max
431
432#endif //TASKMANGERIO_PLATFORMDETERMINATION_H
TimerTask * atomicReadPtr(TimerTaskAtomicPtr *pPtr)
Definition TaskPlatformDeps.h:106
void atomicWritePtr(TimerTaskAtomicPtr *pPtr, TimerTask *volatile newValue)
Definition TaskPlatformDeps.h:116
void atomicWriteBool(TmAtomicBool *pPtr, bool newVal)
Definition TaskPlatformDeps.h:95
bool atomicSwapBool(volatile bool *ptr, bool expected, bool newValue)
Definition TaskPlatformDeps.h:84
bool atomicReadBool(TmAtomicBool *pPtr)
Definition TaskPlatformDeps.h:91
Definition TaskTypes.h:163