diff --git a/cores/esp32/Schedule.cpp b/cores/esp32/Schedule.cpp new file mode 100644 index 00000000000..27b9731954d --- /dev/null +++ b/cores/esp32/Schedule.cpp @@ -0,0 +1,78 @@ +#include "Schedule.h" + +struct scheduled_fn_t +{ + scheduled_fn_t* mNext; + std::function mFunc; +}; + +static scheduled_fn_t* sFirst = 0; +static scheduled_fn_t* sLast = 0; + +static scheduled_fn_t* sFirstUnused = 0; +static scheduled_fn_t* sLastUnused = 0; + +static int sCount = 0; + +static scheduled_fn_t* get_fn() { + scheduled_fn_t* result = NULL; + // try to get an item from unused items list + if (sFirstUnused) { + result = sFirstUnused; + sFirstUnused = result->mNext; + if (sFirstUnused == NULL) { + sLastUnused = NULL; + } + } + // if no unused items, and count not too high, allocate a new one + else if (sCount != SCHEDULED_FN_MAX_COUNT) { + result = new scheduled_fn_t; + result->mNext = NULL; + ++sCount; + } + return result; +} + +static void recycle_fn(scheduled_fn_t* fn) +{ + if (!sLastUnused) { + sFirstUnused = fn; + } + else { + sLastUnused->mNext = fn; + } + fn->mNext = NULL; + sLastUnused = fn; +} + +bool schedule_function(std::function fn) +{ + scheduled_fn_t* item = get_fn(); + if (!item) { + return false; + } + item->mFunc = fn; + item->mNext = NULL; + if (!sFirst) { + sFirst = item; + } + else { + sLast->mNext = item; + } + sLast = item; + return true; +} + +void run_scheduled_functions() +{ + scheduled_fn_t* rFirst = sFirst; + sFirst = NULL; + sLast = NULL; + while (rFirst) { + scheduled_fn_t* item = rFirst; + rFirst = item->mNext; + item->mFunc(); + item->mFunc = std::function(); + recycle_fn(item); + } +} diff --git a/cores/esp32/Schedule.h b/cores/esp32/Schedule.h new file mode 100644 index 00000000000..3399972945d --- /dev/null +++ b/cores/esp32/Schedule.h @@ -0,0 +1,27 @@ +#ifndef ESP_SCHEDULE_H +#define ESP_SCHEDULE_H + +#include + +#define SCHEDULED_FN_MAX_COUNT 32 +#define SCHEDULED_FN_INITIAL_COUNT 4 + +// Warning +// This API is not considered stable. +// Function signatures will change. +// You have been warned. + +// Run given function next time `loop` function returns, +// or `run_scheduled_functions` is called. +// Use std::bind to pass arguments to a function, or call a class member function. +// Note: there is no mechanism for cancelling scheduled functions. +// Keep that in mind when binding functions to objects which may have short lifetime. +// Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT. +bool schedule_function(std::function fn); + +// Run all scheduled functions. +// Use this function if your are not using `loop`, or `loop` does not return +// on a regular basis. +void run_scheduled_functions(); + +#endif //ESP_SCHEDULE_H diff --git a/cores/esp32/main.cpp b/cores/esp32/main.cpp index 0cba93ee0ec..702404f6b5d 100644 --- a/cores/esp32/main.cpp +++ b/cores/esp32/main.cpp @@ -1,6 +1,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "Arduino.h" +#include "Schedule.h" #if CONFIG_AUTOSTART_ARDUINO @@ -16,6 +17,7 @@ void loopTask(void *pvParameters) for(;;) { micros(); //update overflow loop(); + run_scheduled_functions(); } } diff --git a/libraries/Ticker/src/Ticker.cpp b/libraries/Ticker/src/Ticker.cpp index ce5cf69332c..8cbf432c377 100644 --- a/libraries/Ticker/src/Ticker.cpp +++ b/libraries/Ticker/src/Ticker.cpp @@ -54,5 +54,18 @@ void Ticker::detach() { esp_timer_stop(_timer); esp_timer_delete(_timer); _timer = nullptr; + _callback_function = nullptr; } } + +void Ticker::_static_callback(void* arg){ + Ticker* _this = (Ticker*)arg; + if (_this == nullptr) + { + return; + } + if (_this->_callback_function) + { + _this->_callback_function(); + } +} diff --git a/libraries/Ticker/src/Ticker.h b/libraries/Ticker/src/Ticker.h index 82804e0f37d..0c1a54f3d2c 100644 --- a/libraries/Ticker/src/Ticker.h +++ b/libraries/Ticker/src/Ticker.h @@ -25,6 +25,9 @@ #ifndef TICKER_H #define TICKER_H +#include +#include "Schedule.h" + extern "C" { #include "esp_timer.h" } @@ -36,15 +39,28 @@ class Ticker ~Ticker(); typedef void (*callback_t)(void); typedef void (*callback_with_arg_t)(void*); + typedef std::function callback_function_t; + + void attach_scheduled(float seconds, callback_function_t callback) + { + attach(seconds,std::bind(schedule_function, callback)); + } + + void attach(float seconds, callback_function_t callback) + { + _callback_function = callback; + attach(seconds, _static_callback, (void*)this); + } - void attach(float seconds, callback_t callback) + void attach_ms_scheduled(uint32_t milliseconds, callback_function_t callback) { - _attach_ms(seconds * 1000, true, reinterpret_cast(callback), 0); + attach_ms(milliseconds, std::bind(schedule_function, callback)); } - void attach_ms(uint32_t milliseconds, callback_t callback) + void attach_ms(uint32_t milliseconds, callback_function_t callback) { - _attach_ms(milliseconds, true, reinterpret_cast(callback), 0); + _callback_function = callback; + attach_ms(milliseconds, _static_callback, (void*)this); } template @@ -66,14 +82,26 @@ class Ticker _attach_ms(milliseconds, true, reinterpret_cast(callback), arg32); } - void once(float seconds, callback_t callback) + void once_scheduled(float seconds, callback_function_t callback) { - _attach_ms(seconds * 1000, false, reinterpret_cast(callback), 0); + once(seconds, std::bind(schedule_function, callback)); } - void once_ms(uint32_t milliseconds, callback_t callback) + void once(float seconds, callback_function_t callback) { - _attach_ms(milliseconds, false, reinterpret_cast(callback), 0); + _callback_function = callback; + once(seconds, _static_callback, (void*)this); + } + + void once_ms_scheduled(uint32_t milliseconds, callback_function_t callback) + { + once_ms(milliseconds, std::bind(schedule_function, callback)); + } + + void once_ms(uint32_t milliseconds, callback_function_t callback) + { + _callback_function = callback; + once_ms(milliseconds, _static_callback, (void*)this); } template @@ -97,10 +125,11 @@ class Ticker protected: void _attach_ms(uint32_t milliseconds, bool repeat, callback_with_arg_t callback, uint32_t arg); - + static void _static_callback (void* arg); protected: esp_timer_handle_t _timer; + callback_function_t _callback_function = nullptr; };