diff --git a/CMakeLists.txt b/CMakeLists.txt index 227a5568638..6296db68bcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ set(CORE_SRCS cores/esp32/MD5Builder.cpp cores/esp32/Print.cpp cores/esp32/stdlib_noniso.c + cores/esp32/Schedule.cpp cores/esp32/Stream.cpp cores/esp32/StreamString.cpp cores/esp32/wiring_pulse.c diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h index 98e0176f348..34d714ee48b 100644 --- a/cores/esp32/Arduino.h +++ b/cores/esp32/Arduino.h @@ -159,6 +159,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); #include "Udp.h" #include "HardwareSerial.h" #include "Esp.h" +#include "Schedule.h" using std::isinf; using std::isnan; 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 3a455c8a878..0a3ca43b60b 100644 --- a/cores/esp32/main.cpp +++ b/cores/esp32/main.cpp @@ -17,6 +17,7 @@ void loopTask(void *pvParameters) esp_task_wdt_reset(); } loop(); + run_scheduled_functions(); } }