From 55ecd587511d12d1d8c934eb42fe7ca3e270fe50 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 09:38:07 +0200 Subject: [PATCH 01/14] Remove special support for FunctionalInterrupt from core interrupt handling: - VIP treatment in general attach/detach/handling looks untidy: extern symbols without matching header include but copy&paste special under-the-hood c++ delete support, where everyone else has to do their own resource tracking as usual. - FunctionalInterrupt is not used by anything inside core ESP32 Arduino for 8 months now, it can be a library, which reduces precious core size for everyone else. This reverts commit ea61563c690ea4c41cc8cfa808799f84bcfa0540. --- CMakeLists.txt | 1 - cores/esp32/esp32-hal-gpio.c | 23 ++----------------- .../FunctionalInterrupt.cpp | 2 +- .../FunctionalInterrupt.h | 0 .../FunctionalInterrupt.ino | 8 +++---- 5 files changed, 7 insertions(+), 27 deletions(-) rename {cores/esp32 => libraries/ESP32/examples/GPIO/FunctionalInterrupt}/FunctionalInterrupt.cpp (97%) rename {cores/esp32 => libraries/ESP32/examples/GPIO/FunctionalInterrupt}/FunctionalInterrupt.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 227a5568638..86a24ab01fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ set(CORE_SRCS cores/esp32/esp32-hal-uart.c cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp - cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/IPAddress.cpp cores/esp32/IPv6Address.cpp diff --git a/cores/esp32/esp32-hal-gpio.c b/cores/esp32/esp32-hal-gpio.c index d22af774c81..1870eb1676f 100644 --- a/cores/esp32/esp32-hal-gpio.c +++ b/cores/esp32/esp32-hal-gpio.c @@ -74,7 +74,6 @@ typedef void (*voidFuncPtrArg)(void*); typedef struct { voidFuncPtr fn; void* arg; - bool functional; } InterruptHandle_t; static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,}; @@ -239,9 +238,7 @@ static void IRAM_ATTR __onPinInterrupt() } } -extern void cleanupFunctional(void* arg); - -extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional) +extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int intr_type) { static bool interrupt_initialized = false; @@ -250,14 +247,8 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle); } - // if new attach without detach remove old info - if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) - { - cleanupFunctional(__pinInterruptHandlers[pin].arg); - } __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; __pinInterruptHandlers[pin].arg = arg; - __pinInterruptHandlers[pin].functional = functional; esp_intr_disable(gpio_intr_handle); if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU @@ -269,25 +260,15 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, esp_intr_enable(gpio_intr_handle); } -extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type) -{ - __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); -} - extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) { - __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); + __attachInterruptArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type); } extern void __detachInterrupt(uint8_t pin) { esp_intr_disable(gpio_intr_handle); - if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) - { - cleanupFunctional(__pinInterruptHandlers[pin].arg); - } __pinInterruptHandlers[pin].fn = NULL; __pinInterruptHandlers[pin].arg = NULL; - __pinInterruptHandlers[pin].functional = false; GPIO.pin[pin].int_ena = 0; GPIO.pin[pin].int_type = 0; diff --git a/cores/esp32/FunctionalInterrupt.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp similarity index 97% rename from cores/esp32/FunctionalInterrupt.cpp rename to libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp index d2e6dfd4236..97bf239eb51 100644 --- a/cores/esp32/FunctionalInterrupt.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp @@ -6,7 +6,7 @@ */ #include "FunctionalInterrupt.h" -#include "Arduino.h" +#include typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtrArg)(void*); diff --git a/cores/esp32/FunctionalInterrupt.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h similarity index 100% rename from cores/esp32/FunctionalInterrupt.h rename to libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 0e9f97414bb..c076745af76 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,5 +1,5 @@ #include -#include +#include "FunctionalInterrupt.h" #define BUTTON1 16 #define BUTTON2 17 @@ -29,8 +29,8 @@ public: private: const uint8_t PIN; - volatile uint32_t numberKeyPresses; - volatile bool pressed; + volatile uint32_t numberKeyPresses; + volatile bool pressed; }; Button button1(BUTTON1); @@ -38,7 +38,7 @@ Button button2(BUTTON2); void setup() { - Serial.begin(115200); + Serial.begin(115200); } void loop() { From 1923fd3728c1643137267137abbbaadbd1c9f8c6 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 13:10:02 +0200 Subject: [PATCH 02/14] Add supporting function for interrupt arg memory management, linke with functional interrupts. --- cores/esp32/esp32-hal-gpio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cores/esp32/esp32-hal-gpio.c b/cores/esp32/esp32-hal-gpio.c index 1870eb1676f..a7708ef63e7 100644 --- a/cores/esp32/esp32-hal-gpio.c +++ b/cores/esp32/esp32-hal-gpio.c @@ -275,6 +275,10 @@ extern void __detachInterrupt(uint8_t pin) esp_intr_enable(gpio_intr_handle); } +extern InterruptHandle_t* __getInterruptHandler(uint8_t pin) { + return (pin < GPIO_PIN_COUNT) ? &__pinInterruptHandlers[pin] : NULL; +} + extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); From fb8e91847e3338b756a7ebed7ddb49e2bdc298b6 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 13:12:22 +0200 Subject: [PATCH 03/14] Bring back FunctionalInterrupt, and ScheduledFunctions from ESP8266, as example code. It should be decided whether to reinstate these in the core, or make them an optional library. --- .../FunctionalInterrupt.cpp | 44 ------- .../FunctionalInterrupt/FunctionalInterrupt.h | 20 --- .../FunctionalInterrupt.ino | 18 ++- .../FunctionalInterrupts.cpp | 121 ++++++++++++++++++ .../FunctionalInterrupts.h | 37 ++++++ .../GPIO/FunctionalInterrupt/Schedule.cpp | 78 +++++++++++ .../GPIO/FunctionalInterrupt/Schedule.h | 27 ++++ .../ScheduledFunctions.cpp | 117 +++++++++++++++++ .../FunctionalInterrupt/ScheduledFunctions.h | 51 ++++++++ 9 files changed, 445 insertions(+), 68 deletions(-) delete mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp delete mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp create mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp deleted file mode 100644 index 97bf239eb51..00000000000 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * FunctionalInterrupt.cpp - * - * Created on: 8 jul. 2018 - * Author: Herman - */ - -#include "FunctionalInterrupt.h" -#include - -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -extern "C" -{ - extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional); -} - -void IRAM_ATTR interruptFunctional(void* arg) -{ - InterruptArgStructure* localArg = (InterruptArgStructure*)arg; - if (localArg->interruptFunction) - { - localArg->interruptFunction(); - } -} - -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) -{ - // use the local interrupt routine which takes the ArgStructure as argument - __attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true); -} - -extern "C" -{ - void cleanupFunctional(void* arg) - { - delete (InterruptArgStructure*)arg; - } -} - - - - diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h deleted file mode 100644 index b5e3181f986..00000000000 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * FunctionalInterrupt.h - * - * Created on: 8 jul. 2018 - * Author: Herman - */ - -#ifndef CORE_CORE_FUNCTIONALINTERRUPT_H_ -#define CORE_CORE_FUNCTIONALINTERRUPT_H_ - -#include - -struct InterruptArgStructure { - std::function interruptFunction; -}; - -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); - - -#endif /* CORE_CORE_FUNCTIONALINTERRUPT_H_ */ diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index c076745af76..5f631069914 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,21 +1,31 @@ #include -#include "FunctionalInterrupt.h" +#include "FunctionalInterrupts.h" +#if defined(ESP8266) || defined(ARDUINO_D1_MINI32) +#define BUTTON1 D3 +#define BUTTON2 D4 +#else #define BUTTON1 16 #define BUTTON2 17 +#endif class Button { public: - Button(uint8_t reqPin) : PIN(reqPin){ + Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING); }; ~Button() { - detachInterrupt(PIN); + detachFunctionalInterrupt(PIN); } - void IRAM_ATTR isr() { +#if defined(ESP8266) + void ICACHE_RAM_ATTR isr() +#elif defined(ESP32) + void IRAM_ATTR isr() +#endif + { numberKeyPresses += 1; pressed = true; } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp new file mode 100644 index 00000000000..3426e146770 --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -0,0 +1,121 @@ +#include "FunctionalInterrupts.h" +#include "Schedule.h" +#include "Arduino.h" + +#if defined(ESP8266) + +// Duplicate typedefs from core_esp8266_wiring_digital.cpp +// Keep in sync +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); + +typedef struct { + uint8_t mode; + voidFuncPtr fn; + void* arg; +} interrupt_handler_t; + +// Helper functions for Functional interrupt routines +extern "C" interrupt_handler_t* __getInterruptHandler(uint8_t pin); + +#elif defined(ESP32) + +// Duplicate typedefs from esp32-hal-gpio.c +// Keep in sync +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void*); +typedef struct { + voidFuncPtr fn; + void* arg; +} InterruptHandle_t; + +// Helper functions for Functional interrupt routines +extern "C" InterruptHandle_t* __getInterruptHandler(uint8_t pin); + +#endif + +void ICACHE_RAM_ATTR interruptFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + if (localArg->interruptInfo) + { + localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); + localArg->interruptInfo->micro = micros(); + } + if (localArg->functionInfo->reqScheduledFunction) + { + schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); + } + if (localArg->functionInfo->reqFunction) + { + localArg->functionInfo->reqFunction(); + } +} + + void cleanupFunctional(void* arg) + { + ArgStructure* localArg = static_cast(arg); + delete localArg; + } + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) +{ + // use the local interrupt routine which takes the ArgStructure as argument + +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; + + ArgStructure* as = new ArgStructure; + as->functionInfo = fi; + + ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); +} + +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) +{ +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + + InterruptInfo* ii = new InterruptInfo(pin); + + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; + + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; + + ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); +} + +void detachFunctionalInterrupt(uint8_t pin) +{ +#if defined(ESP8266) + interrupt_handler_t* handler = __getInterruptHandler(pin); +#elif defined(ESP32) + InterruptHandle_t* handler = __getInterruptHandler(pin); +#endif + if (handler->arg) + { + cleanupFunctional(handler->arg); + } + ::detachInterrupt (pin); +} + diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h new file mode 100644 index 00000000000..ef75a9525f1 --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -0,0 +1,37 @@ +#ifndef FUNCTIONALINTERRUPTS_H +#define FUNCTIONALINTERRUPTS_H + +#include +#include +#include +#include "ScheduledFunctions.h" + +// Structures for communication + +struct InterruptInfo { + InterruptInfo(uint8_t _pin) : pin(_pin) {} + const uint8_t pin; + uint8_t value = 0; + uint32_t micro = 0; +}; + +struct FunctionInfo { + std::function reqFunction = nullptr; + std::function reqScheduledFunction = nullptr; +}; + +struct ArgStructure { + ~ArgStructure() + { + delete functionInfo; + delete interruptInfo; + } + InterruptInfo* interruptInfo = nullptr; + FunctionInfo* functionInfo = nullptr; +}; + +void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); +void detachFunctionalInterrupt(uint8_t pin); + +#endif //INTERRUPTS_H diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp new file mode 100644 index 00000000000..27b9731954d --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/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/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h new file mode 100644 index 00000000000..3399972945d --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/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/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp new file mode 100644 index 00000000000..25bc58db61c --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp @@ -0,0 +1,117 @@ +/* + * ScheduledFunctions.cpp + * + * Created on: 27 apr. 2018 + * Author: Herman + */ +#include "ScheduledFunctions.h" + +std::list ScheduledFunctions::scheduledFunctions; + +ScheduledFunctions::ScheduledFunctions() +:ScheduledFunctions(UINT_MAX) +{ +} + +ScheduledFunctions::ScheduledFunctions(unsigned int reqMax) +{ + maxElements = reqMax; +} + +ScheduledFunctions::~ScheduledFunctions() { +} + +ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front) +{ + if (countElements >= maxElements) + { + return nullptr; + } + else + { + countElements++; + if (front) + { + scheduledFunctions.push_front(se); + return scheduledFunctions.begin()->registration; + } + else + { + scheduledFunctions.push_back(se); + return scheduledFunctions.rbegin()->registration; + } + } +} + +std::list::iterator ScheduledFunctions::eraseElement(std::list::iterator it) +{ + countElements--; + return scheduledFunctions.erase(it); +} + +bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) +{ + return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); +} + +bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) +{ + return scheduleFunction(sf, false, false); +} + +ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) +{ + return insertElement({this,continuous,std::make_shared(1),sf},front); +} + +void ScheduledFunctions::runScheduledFunctions() +{ + auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions + auto it = scheduledFunctions.begin(); + while (it != lastElement) + { + bool erase = false; + if (it->registration == nullptr) + { + it->function(); + } + else + { + if (it->registration.use_count() > 1) + { + it->function(); + } + else + { + erase = true; + } + } + if ((!it->continuous) || (erase)) + { + it = it->_this->eraseElement(it); + } + else + { + it++; + } + } +} + +void ScheduledFunctions::removeFunction(ScheduledRegistration sr) +{ + auto it = scheduledFunctions.begin(); + bool removed = false; + while ((!removed) && (it != scheduledFunctions.end())) + { + if (it->registration == sr) + { + it = eraseElement(it); + removed = true; + } + else + { + it++; + } + } +} + diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h new file mode 100644 index 00000000000..01296353641 --- /dev/null +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h @@ -0,0 +1,51 @@ +/* + * ScheduledFunctions.h + * + * Created on: 27 apr. 2018 + * Author: Herman + */ +#include "Arduino.h" +#include "Schedule.h" + +#include +#include +#include +#include + +#ifndef SCHEDULEDFUNCTIONS_H_ +#define SCHEDULEDFUNCTIONS_H_ + +typedef std::function ScheduledFunction; +typedef std::shared_ptr ScheduledRegistration; + +class ScheduledFunctions { + +public: + ScheduledFunctions(); + ScheduledFunctions(unsigned int reqMax); + virtual ~ScheduledFunctions(); + + struct ScheduledElement + { + ScheduledFunctions* _this; + bool continuous; + ScheduledRegistration registration; + ScheduledFunction function; + }; + + ScheduledRegistration insertElement(ScheduledElement se, bool front); + std::list::iterator eraseElement(std::list::iterator); + bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); + bool scheduleFunction(ScheduledFunction sf); + ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); + static void runScheduledFunctions(); + void removeFunction(ScheduledRegistration sr); + + + static std::list scheduledFunctions; + unsigned int maxElements; + unsigned int countElements = 0; + +}; + +#endif /* SCHEDULEDFUNCTIONS_H_ */ From 263ed08dee6df4d7dc7c2d068831fc069c513089 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 14:03:04 +0200 Subject: [PATCH 04/14] Ridiculous port number mistake. --- .../GPIO/FunctionalInterrupt/FunctionalInterrupt.ino | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 5f631069914..491d1962ff7 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,12 +1,15 @@ #include #include "FunctionalInterrupts.h" -#if defined(ESP8266) || defined(ARDUINO_D1_MINI32) -#define BUTTON1 D3 -#define BUTTON2 D4 -#else +#if defined(ESP32) #define BUTTON1 16 #define BUTTON2 17 +#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) +#define BUTTON1 D4 +#define BUTTON2 D3 +#else +#define BUTTON1 2 +#define BUTTON2 0 #endif class Button From c031b1de7a21e410791743728aae8169170a3403 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 17:42:18 +0200 Subject: [PATCH 05/14] Apply astyle to example INO. --- .../FunctionalInterrupt.ino | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 491d1962ff7..b386b1d83f6 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -12,38 +12,37 @@ #define BUTTON2 0 #endif -class Button -{ -public: - Button(uint8_t reqPin) : PIN(reqPin) { - pinMode(PIN, INPUT_PULLUP); - attachInterrupt(PIN, std::bind(&Button::isr,this), FALLING); - }; - ~Button() { - detachFunctionalInterrupt(PIN); - } +class Button { + public: + Button(uint8_t reqPin) : PIN(reqPin) { + pinMode(PIN, INPUT_PULLUP); + attachInterrupt(PIN, std::bind(&Button::isr, this), FALLING); + }; + ~Button() { + detachFunctionalInterrupt(PIN); + } #if defined(ESP8266) - void ICACHE_RAM_ATTR isr() + void ICACHE_RAM_ATTR isr() #elif defined(ESP32) - void IRAM_ATTR isr() + void IRAM_ATTR isr() #endif - { - numberKeyPresses += 1; - pressed = true; - } - - void checkPressed() { - if (pressed) { - Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); - pressed = false; - } - } - -private: - const uint8_t PIN; - volatile uint32_t numberKeyPresses; - volatile bool pressed; + { + numberKeyPresses += 1; + pressed = true; + } + + void checkPressed() { + if (pressed) { + Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); + pressed = false; + } + } + + private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses; + volatile bool pressed; }; Button button1(BUTTON1); @@ -51,10 +50,10 @@ Button button2(BUTTON2); void setup() { - Serial.begin(115200); + Serial.begin(115200); } void loop() { - button1.checkPressed(); - button2.checkPressed(); + button1.checkPressed(); + button2.checkPressed(); } From 7119d140246f7bc62b3067615837c58bcf7ee00b Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Thu, 2 May 2019 21:43:27 +0200 Subject: [PATCH 06/14] Remove ScheduledFunctions.(h|cpp), per comment https://github.com/esp8266/Arduino/pull/6038#issuecomment-488758509 --- .../FunctionalInterrupts.h | 1 - .../ScheduledFunctions.cpp | 117 ------------------ .../FunctionalInterrupt/ScheduledFunctions.h | 51 -------- 3 files changed, 169 deletions(-) delete mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp delete mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index ef75a9525f1..9c5d554e273 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -4,7 +4,6 @@ #include #include #include -#include "ScheduledFunctions.h" // Structures for communication diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp deleted file mode 100644 index 25bc58db61c..00000000000 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ScheduledFunctions.cpp - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "ScheduledFunctions.h" - -std::list ScheduledFunctions::scheduledFunctions; - -ScheduledFunctions::ScheduledFunctions() -:ScheduledFunctions(UINT_MAX) -{ -} - -ScheduledFunctions::ScheduledFunctions(unsigned int reqMax) -{ - maxElements = reqMax; -} - -ScheduledFunctions::~ScheduledFunctions() { -} - -ScheduledRegistration ScheduledFunctions::insertElement(ScheduledElement se, bool front) -{ - if (countElements >= maxElements) - { - return nullptr; - } - else - { - countElements++; - if (front) - { - scheduledFunctions.push_front(se); - return scheduledFunctions.begin()->registration; - } - else - { - scheduledFunctions.push_back(se); - return scheduledFunctions.rbegin()->registration; - } - } -} - -std::list::iterator ScheduledFunctions::eraseElement(std::list::iterator it) -{ - countElements--; - return scheduledFunctions.erase(it); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) -{ - return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); -} - -bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) -{ - return scheduleFunction(sf, false, false); -} - -ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) -{ - return insertElement({this,continuous,std::make_shared(1),sf},front); -} - -void ScheduledFunctions::runScheduledFunctions() -{ - auto lastElement = scheduledFunctions.end(); // do not execute elements added during runScheduledFunctions - auto it = scheduledFunctions.begin(); - while (it != lastElement) - { - bool erase = false; - if (it->registration == nullptr) - { - it->function(); - } - else - { - if (it->registration.use_count() > 1) - { - it->function(); - } - else - { - erase = true; - } - } - if ((!it->continuous) || (erase)) - { - it = it->_this->eraseElement(it); - } - else - { - it++; - } - } -} - -void ScheduledFunctions::removeFunction(ScheduledRegistration sr) -{ - auto it = scheduledFunctions.begin(); - bool removed = false; - while ((!removed) && (it != scheduledFunctions.end())) - { - if (it->registration == sr) - { - it = eraseElement(it); - removed = true; - } - else - { - it++; - } - } -} - diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h deleted file mode 100644 index 01296353641..00000000000 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/ScheduledFunctions.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ScheduledFunctions.h - * - * Created on: 27 apr. 2018 - * Author: Herman - */ -#include "Arduino.h" -#include "Schedule.h" - -#include -#include -#include -#include - -#ifndef SCHEDULEDFUNCTIONS_H_ -#define SCHEDULEDFUNCTIONS_H_ - -typedef std::function ScheduledFunction; -typedef std::shared_ptr ScheduledRegistration; - -class ScheduledFunctions { - -public: - ScheduledFunctions(); - ScheduledFunctions(unsigned int reqMax); - virtual ~ScheduledFunctions(); - - struct ScheduledElement - { - ScheduledFunctions* _this; - bool continuous; - ScheduledRegistration registration; - ScheduledFunction function; - }; - - ScheduledRegistration insertElement(ScheduledElement se, bool front); - std::list::iterator eraseElement(std::list::iterator); - bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); - bool scheduleFunction(ScheduledFunction sf); - ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); - static void runScheduledFunctions(); - void removeFunction(ScheduledRegistration sr); - - - static std::list scheduledFunctions; - unsigned int maxElements; - unsigned int countElements = 0; - -}; - -#endif /* SCHEDULEDFUNCTIONS_H_ */ From 556f9b9095853914f217e504b9b1c4f77e47f461 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 12:10:17 +0200 Subject: [PATCH 07/14] Invented void* detachInterruptArg() that returns the argument given in attachInterruptArg(). This is sufficient for resource management - the function has static duration anyway. --- cores/esp32/esp32-hal-gpio.c | 13 +-- cores/esp32/esp32-hal-gpio.h | 3 +- .../FunctionalInterrupts.cpp | 82 +++++-------------- 3 files changed, 28 insertions(+), 70 deletions(-) diff --git a/cores/esp32/esp32-hal-gpio.c b/cores/esp32/esp32-hal-gpio.c index a7708ef63e7..82dbf818638 100644 --- a/cores/esp32/esp32-hal-gpio.c +++ b/cores/esp32/esp32-hal-gpio.c @@ -75,7 +75,7 @@ typedef struct { voidFuncPtr fn; void* arg; } InterruptHandle_t; -static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,}; +static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = { {0,0}, }; #include "driver/rtc_io.h" @@ -275,15 +275,16 @@ extern void __detachInterrupt(uint8_t pin) esp_intr_enable(gpio_intr_handle); } -extern InterruptHandle_t* __getInterruptHandler(uint8_t pin) { - return (pin < GPIO_PIN_COUNT) ? &__pinInterruptHandlers[pin] : NULL; +extern void* __detachInterruptArg(uint8_t pin) { + void* arg = (pin < GPIO_PIN_COUNT) ? __pinInterruptHandlers[pin].arg : NULL; + __detachInterrupt(pin); + return arg; } - extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite"))); extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead"))); extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt"))); +extern void detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt"))); extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg"))); -extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); - +extern void* detachInterruptArg(uint8_t pin) __attribute__((weak, alias("__detachInterruptArg"))); diff --git a/cores/esp32/esp32-hal-gpio.h b/cores/esp32/esp32-hal-gpio.h index daa9f6e66fa..ff9ddc56c79 100644 --- a/cores/esp32/esp32-hal-gpio.h +++ b/cores/esp32/esp32-hal-gpio.h @@ -79,8 +79,9 @@ void digitalWrite(uint8_t pin, uint8_t val); int digitalRead(uint8_t pin); void attachInterrupt(uint8_t pin, void (*)(void), int mode); -void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode); void detachInterrupt(uint8_t pin); +void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); +void* detachInterruptArg(uint8_t pin); #ifdef __cplusplus } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 3426e146770..b1725f84c5f 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -2,38 +2,6 @@ #include "Schedule.h" #include "Arduino.h" -#if defined(ESP8266) - -// Duplicate typedefs from core_esp8266_wiring_digital.cpp -// Keep in sync -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); - -typedef struct { - uint8_t mode; - voidFuncPtr fn; - void* arg; -} interrupt_handler_t; - -// Helper functions for Functional interrupt routines -extern "C" interrupt_handler_t* __getInterruptHandler(uint8_t pin); - -#elif defined(ESP32) - -// Duplicate typedefs from esp32-hal-gpio.c -// Keep in sync -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); -typedef struct { - voidFuncPtr fn; - void* arg; -} InterruptHandle_t; - -// Helper functions for Functional interrupt routines -extern "C" InterruptHandle_t* __getInterruptHandler(uint8_t pin); - -#endif - void ICACHE_RAM_ATTR interruptFunctional(void* arg) { ArgStructure* localArg = static_cast(arg); @@ -44,7 +12,9 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) } if (localArg->functionInfo->reqScheduledFunction) { - schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); + schedule_function( + [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, + interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); } if (localArg->functionInfo->reqFunction) { @@ -52,24 +22,20 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) } } - void cleanupFunctional(void* arg) - { - ArgStructure* localArg = static_cast(arg); - delete localArg; - } +void cleanupFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + delete localArg; +} void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) { // use the local interrupt routine which takes the ArgStructure as argument -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } FunctionInfo* fi = new FunctionInfo; @@ -78,19 +44,15 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode ArgStructure* as = new ArgStructure; as->functionInfo = fi; - ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); + attachInterruptArg (pin, interruptFunctional, as, mode); } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } InterruptInfo* ii = new InterruptInfo(pin); @@ -102,20 +64,14 @@ void attachScheduledInterrupt(uint8_t pin, std::function sc as->interruptInfo = ii; as->functionInfo = fi; - ::attachInterruptArg (pin, static_cast(interruptFunctional), as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void detachFunctionalInterrupt(uint8_t pin) { -#if defined(ESP8266) - interrupt_handler_t* handler = __getInterruptHandler(pin); -#elif defined(ESP32) - InterruptHandle_t* handler = __getInterruptHandler(pin); -#endif - if (handler->arg) + void* localArg = detachInterruptArg(pin); + if (localArg) { - cleanupFunctional(handler->arg); + cleanupFunctional(localArg); } - ::detachInterrupt (pin); } - From f8e0fcbbd36a2bf6dcfc2db453b3cff393ee7632 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 14:39:30 +0200 Subject: [PATCH 08/14] Modified example to showcase how general FunctionalInterrupt uses violate the ISR in ICACHE_RAM rule (ESP8266 core catches this). --- .../FunctionalInterrupt.ino | 38 +++++++++++++++---- .../FunctionalInterrupts.cpp | 17 ++------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index b386b1d83f6..aae06082ebf 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,4 +1,5 @@ #include +#include #include "FunctionalInterrupts.h" #if defined(ESP32) @@ -16,10 +17,15 @@ class Button { public: Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); - attachInterrupt(PIN, std::bind(&Button::isr, this), FALLING); + // Arduino C API: + attachInterruptArg(PIN, [](void* self) { static_cast(self)->isr(); }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 + // FunctionalInterrupts API: + //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 + //attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { Serial.print("Pin "); Serial.println(ii.pin); isr(); }, FALLING); // works on ESP32; works on ESP8266 }; ~Button() { - detachFunctionalInterrupt(PIN); + detachInterrupt(PIN); } #if defined(ESP8266) @@ -32,6 +38,15 @@ class Button { pressed = true; } +#if defined(ESP8266) + static void ICACHE_RAM_ATTR isr_static(Button* const self) +#elif defined(ESP32) + static void IRAM_ATTR isr_static(Button* const self) +#endif + { + self->isr(); + } + void checkPressed() { if (pressed) { Serial.printf("Button on pin %u has been pressed %u times\n", PIN, numberKeyPresses); @@ -41,19 +56,26 @@ class Button { private: const uint8_t PIN; - volatile uint32_t numberKeyPresses; - volatile bool pressed; + volatile uint32_t numberKeyPresses = 0; + volatile bool pressed = false; }; -Button button1(BUTTON1); -Button button2(BUTTON2); +Button* button1; +Button* button2; void setup() { Serial.begin(115200); + schedule_function([]() { Serial.println("Scheduled function"); }); + Serial.println("FunctionalInterrupt test/example"); + + button1 = new Button(BUTTON1); + button2 = new Button(BUTTON2); + + Serial.println("setup() complete"); } void loop() { - button1.checkPressed(); - button2.checkPressed(); + button1->checkPressed(); + button2->checkPressed(); } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index b1725f84c5f..1867e7bd924 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -1,5 +1,5 @@ #include "FunctionalInterrupts.h" -#include "Schedule.h" +#include #include "Arduino.h" void ICACHE_RAM_ATTR interruptFunctional(void* arg) @@ -33,10 +33,7 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode // use the local interrupt routine which takes the ArgStructure as argument void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); FunctionInfo* fi = new FunctionInfo; fi->reqFunction = intRoutine; @@ -50,10 +47,7 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); InterruptInfo* ii = new InterruptInfo(pin); @@ -70,8 +64,5 @@ void attachScheduledInterrupt(uint8_t pin, std::function sc void detachFunctionalInterrupt(uint8_t pin) { void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } + if (localArg) cleanupFunctional(localArg); } From eb17194d27d554ebc24b5e634728afaa3a12a627 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:26:50 +0200 Subject: [PATCH 09/14] Direct call or scheduled is either-or. --- .../FunctionalInterrupts.cpp | 4 +-- .../FunctionalInterrupts.h | 26 +++++++++---------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 1867e7bd924..6d990440be1 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -1,6 +1,6 @@ #include "FunctionalInterrupts.h" #include -#include "Arduino.h" +#include void ICACHE_RAM_ATTR interruptFunctional(void* arg) { @@ -16,7 +16,7 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); } - if (localArg->functionInfo->reqFunction) + else if (localArg->functionInfo->reqFunction) { localArg->functionInfo->reqFunction(); } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index 9c5d554e273..b1867f73ad2 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -1,32 +1,30 @@ #ifndef FUNCTIONALINTERRUPTS_H #define FUNCTIONALINTERRUPTS_H -#include -#include #include // Structures for communication struct InterruptInfo { - InterruptInfo(uint8_t _pin) : pin(_pin) {} - const uint8_t pin; - uint8_t value = 0; - uint32_t micro = 0; + InterruptInfo(uint8_t _pin) : pin(_pin) {} + const uint8_t pin; + uint8_t value = 0; + uint32_t micro = 0; }; struct FunctionInfo { std::function reqFunction = nullptr; - std::function reqScheduledFunction = nullptr; + std::function reqScheduledFunction = nullptr; }; struct ArgStructure { - ~ArgStructure() - { - delete functionInfo; - delete interruptInfo; - } - InterruptInfo* interruptInfo = nullptr; - FunctionInfo* functionInfo = nullptr; + ~ArgStructure() + { + delete functionInfo; + delete interruptInfo; + } + InterruptInfo* interruptInfo = nullptr; + FunctionInfo* functionInfo = nullptr; }; void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); From dea238289b5be6d757cabb00cb0dcf40a1409b92 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:32:44 +0200 Subject: [PATCH 10/14] While Schedule.cpp is not part of ESP32 core... --- .../examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino | 4 +++- .../GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index aae06082ebf..46144cf1d49 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -1,5 +1,5 @@ #include -#include +#include "Schedule.h" #include "FunctionalInterrupts.h" #if defined(ESP32) @@ -78,4 +78,6 @@ void setup() { void loop() { button1->checkPressed(); button2->checkPressed(); + + run_scheduled_functions(); } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 6d990440be1..6b644861a8c 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -1,5 +1,5 @@ #include "FunctionalInterrupts.h" -#include +#include "Schedule.h" #include void ICACHE_RAM_ATTR interruptFunctional(void* arg) From ce898dfe00abdc69e7c3c74ed293d8ed5ccf361d Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:43:30 +0200 Subject: [PATCH 11/14] Always apply astyle to examples. --- .../GPIO/FunctionalInterrupt/FunctionalInterrupt.ino | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 46144cf1d49..bc9c07ba3d8 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -18,7 +18,9 @@ class Button { Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); // Arduino C API: - attachInterruptArg(PIN, [](void* self) { static_cast(self)->isr(); }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + attachInterruptArg(PIN, [](void* self) { + static_cast(self)->isr(); + }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 // FunctionalInterrupts API: //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 @@ -44,7 +46,7 @@ class Button { static void IRAM_ATTR isr_static(Button* const self) #endif { - self->isr(); + self->isr(); } void checkPressed() { @@ -66,7 +68,9 @@ Button* button2; void setup() { Serial.begin(115200); - schedule_function([]() { Serial.println("Scheduled function"); }); + schedule_function([]() { + Serial.println("Scheduled function"); + }); Serial.println("FunctionalInterrupt test/example"); button1 = new Button(BUTTON1); From a4000dd98078a27d4d0417cef9a5937959fe9265 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Sun, 5 May 2019 04:00:59 +0200 Subject: [PATCH 12/14] Add Schedule.(h|cpp) from ESP8266 to run off loopTask. (cherry picked from commit d39be670e98e1a99e6675bd3958d9f4a03c74db8) --- CMakeLists.txt | 1 + cores/esp32/Arduino.h | 1 + cores/esp32/Schedule.cpp | 78 ++++++++++++++++++++++++++++++++++++++++ cores/esp32/Schedule.h | 27 ++++++++++++++ cores/esp32/main.cpp | 1 + 5 files changed, 108 insertions(+) create mode 100644 cores/esp32/Schedule.cpp create mode 100644 cores/esp32/Schedule.h 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(); } } From d2ec37c62d9ef1e2275584d0788b94257ef1934f Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 3 May 2019 15:43:30 +0200 Subject: [PATCH 13/14] Always apply astyle to examples. --- .../FunctionalInterrupt.ino | 10 ++- .../FunctionalInterrupts.cpp | 86 +++++++++++-------- .../FunctionalInterrupts.h | 9 +- .../GPIO/FunctionalInterrupt/Schedule.cpp | 36 +++++--- .../GPIO/FunctionalInterrupt/Schedule.h | 8 +- 5 files changed, 89 insertions(+), 60 deletions(-) diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino index 46144cf1d49..bc9c07ba3d8 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino @@ -18,7 +18,9 @@ class Button { Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); // Arduino C API: - attachInterruptArg(PIN, [](void* self) { static_cast(self)->isr(); }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + attachInterruptArg(PIN, [](void* self) { + static_cast(self)->isr(); + }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 // FunctionalInterrupts API: //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 @@ -44,7 +46,7 @@ class Button { static void IRAM_ATTR isr_static(Button* const self) #endif { - self->isr(); + self->isr(); } void checkPressed() { @@ -66,7 +68,9 @@ Button* button2; void setup() { Serial.begin(115200); - schedule_function([]() { Serial.println("Scheduled function"); }); + schedule_function([]() { + Serial.println("Scheduled function"); + }); Serial.println("FunctionalInterrupt test/example"); button1 = new Button(BUTTON1); diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp index 6b644861a8c..a61b24e5e67 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp @@ -4,65 +4,77 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) { - ArgStructure* localArg = static_cast(arg); - if (localArg->interruptInfo) - { - localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); - localArg->interruptInfo->micro = micros(); - } - if (localArg->functionInfo->reqScheduledFunction) - { - schedule_function( - [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, - interruptInfo = *localArg->interruptInfo]() { reqScheduledFunction(interruptInfo); }); - } - else if (localArg->functionInfo->reqFunction) - { - localArg->functionInfo->reqFunction(); - } + ArgStructure* localArg = static_cast(arg); + if (localArg->interruptInfo) + { + localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); + localArg->interruptInfo->micro = micros(); + } + if (localArg->functionInfo->reqScheduledFunction) + { + schedule_function( + [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, + interruptInfo = *localArg->interruptInfo]() + { + reqScheduledFunction(interruptInfo); + }); + } + else if (localArg->functionInfo->reqFunction) + { + localArg->functionInfo->reqFunction(); + } } void cleanupFunctional(void* arg) { - ArgStructure* localArg = static_cast(arg); - delete localArg; + ArgStructure* localArg = static_cast(arg); + delete localArg; } void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) { - // use the local interrupt routine which takes the ArgStructure as argument + // use the local interrupt routine which takes the ArgStructure as argument - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - FunctionInfo* fi = new FunctionInfo; - fi->reqFunction = intRoutine; + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; - ArgStructure* as = new ArgStructure; - as->functionInfo = fi; + ArgStructure* as = new ArgStructure; + as->functionInfo = fi; - attachInterruptArg (pin, interruptFunctional, as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - InterruptInfo* ii = new InterruptInfo(pin); + InterruptInfo* ii = new InterruptInfo(pin); - FunctionInfo* fi = new FunctionInfo; - fi->reqScheduledFunction = scheduledIntRoutine; + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; - attachInterruptArg(pin, interruptFunctional, as, mode); + attachInterruptArg(pin, interruptFunctional, as, mode); } void detachFunctionalInterrupt(uint8_t pin) { - void* localArg = detachInterruptArg(pin); - if (localArg) cleanupFunctional(localArg); + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } } diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h index b1867f73ad2..a0444f4260c 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h @@ -5,19 +5,22 @@ // Structures for communication -struct InterruptInfo { +struct InterruptInfo +{ InterruptInfo(uint8_t _pin) : pin(_pin) {} const uint8_t pin; uint8_t value = 0; uint32_t micro = 0; }; -struct FunctionInfo { +struct FunctionInfo +{ std::function reqFunction = nullptr; std::function reqScheduledFunction = nullptr; }; -struct ArgStructure { +struct ArgStructure +{ ~ArgStructure() { delete functionInfo; diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp index 27b9731954d..c8eb5d706c0 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.cpp @@ -14,18 +14,22 @@ static scheduled_fn_t* sLastUnused = 0; static int sCount = 0; -static scheduled_fn_t* get_fn() { +static scheduled_fn_t* get_fn() +{ scheduled_fn_t* result = NULL; // try to get an item from unused items list - if (sFirstUnused) { + if (sFirstUnused) + { result = sFirstUnused; sFirstUnused = result->mNext; - if (sFirstUnused == NULL) { + 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) { + else if (sCount != SCHEDULED_FN_MAX_COUNT) + { result = new scheduled_fn_t; result->mNext = NULL; ++sCount; @@ -35,10 +39,12 @@ static scheduled_fn_t* get_fn() { static void recycle_fn(scheduled_fn_t* fn) { - if (!sLastUnused) { + if (!sLastUnused) + { sFirstUnused = fn; } - else { + else + { sLastUnused->mNext = fn; } fn->mNext = NULL; @@ -48,15 +54,18 @@ static void recycle_fn(scheduled_fn_t* fn) bool schedule_function(std::function fn) { scheduled_fn_t* item = get_fn(); - if (!item) { + if (!item) + { return false; } item->mFunc = fn; item->mNext = NULL; - if (!sFirst) { + if (!sFirst) + { sFirst = item; } - else { + else + { sLast->mNext = item; } sLast = item; @@ -65,10 +74,11 @@ bool schedule_function(std::function fn) void run_scheduled_functions() { - scheduled_fn_t* rFirst = sFirst; - sFirst = NULL; - sLast = NULL; - while (rFirst) { + scheduled_fn_t* rFirst = sFirst; + sFirst = NULL; + sLast = NULL; + while (rFirst) + { scheduled_fn_t* item = rFirst; rFirst = item->mNext; item->mFunc(); diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h index 3399972945d..0868f27c8c7 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h +++ b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/Schedule.h @@ -6,12 +6,12 @@ #define SCHEDULED_FN_MAX_COUNT 32 #define SCHEDULED_FN_INITIAL_COUNT 4 -// Warning -// This API is not considered stable. +// Warning +// This API is not considered stable. // Function signatures will change. // You have been warned. -// Run given function next time `loop` function returns, +// 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. @@ -19,7 +19,7 @@ // Returns false if the number of scheduled functions exceeds SCHEDULED_FN_MAX_COUNT. bool schedule_function(std::function fn); -// Run all scheduled functions. +// 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(); From ffc4c7d7afc2729e768e803af56bdc988f24ce4e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 6 May 2019 11:07:01 +0200 Subject: [PATCH 14/14] Refactored cores/esp32/FunctionalInterrupt to not support illegal use of non-IRAM ISRs via C++ std::bind, std::function, or lambdas. It is now a follow up to the introduction of Schedule.(h|cpp) into core, which supports safe scheduling of non-IRAM ISRs as they are being scheduled synchronously to loop() in the same task. --- CMakeLists.txt | 1 + cores/esp32/FunctionalInterrupt.cpp | 52 ++++++++++++ .../esp32/FunctionalInterrupt.h | 16 +--- .../FunctionalInterrupts.cpp | 79 ------------------- .../ScheduledInterrupt.ino} | 20 ++--- 5 files changed, 68 insertions(+), 100 deletions(-) create mode 100644 cores/esp32/FunctionalInterrupt.cpp rename libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h => cores/esp32/FunctionalInterrupt.h (55%) delete mode 100644 libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp rename libraries/ESP32/examples/GPIO/{FunctionalInterrupt/FunctionalInterrupt.ino => ScheduledInterrupt/ScheduledInterrupt.ino} (73%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9caeac553b..6296db68bcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ set(CORE_SRCS cores/esp32/esp32-hal-uart.c cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp + cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/IPAddress.cpp cores/esp32/IPv6Address.cpp diff --git a/cores/esp32/FunctionalInterrupt.cpp b/cores/esp32/FunctionalInterrupt.cpp new file mode 100644 index 00000000000..64000739dca --- /dev/null +++ b/cores/esp32/FunctionalInterrupt.cpp @@ -0,0 +1,52 @@ +#include "FunctionalInterrupt.h" +#include "Schedule.h" +#include "Arduino.h" + +void ICACHE_RAM_ATTR interruptFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + if (localArg->interruptInfo) + { + localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); + localArg->interruptInfo->micro = micros(); + } + if (localArg->scheduledFunction) + { + schedule_function( + [scheduledFunction = localArg->scheduledFunction, + interruptInfo = *localArg->interruptInfo]() + { + scheduledFunction(interruptInfo); + }); + } +} + +void cleanupFunctional(void* arg) +{ + ArgStructure* localArg = static_cast(arg); + delete localArg; +} + +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) +{ + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } + + ArgStructure* as = new ArgStructure; + as->interruptInfo = new InterruptInfo(pin); + as->scheduledFunction = scheduledIntRoutine; + + attachInterruptArg(pin, interruptFunctional, as, mode); +} + +void detachFunctionalInterrupt(uint8_t pin) +{ + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } +} diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h b/cores/esp32/FunctionalInterrupt.h similarity index 55% rename from libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h rename to cores/esp32/FunctionalInterrupt.h index a0444f4260c..919302a8995 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.h +++ b/cores/esp32/FunctionalInterrupt.h @@ -1,5 +1,5 @@ -#ifndef FUNCTIONALINTERRUPTS_H -#define FUNCTIONALINTERRUPTS_H +#ifndef CORE_FUNCTIONALINTERRUPT_H +#define CORE_FUNCTIONALINTERRUPT_H #include @@ -13,25 +13,17 @@ struct InterruptInfo uint32_t micro = 0; }; -struct FunctionInfo -{ - std::function reqFunction = nullptr; - std::function reqScheduledFunction = nullptr; -}; - struct ArgStructure { ~ArgStructure() { - delete functionInfo; delete interruptInfo; } InterruptInfo* interruptInfo = nullptr; - FunctionInfo* functionInfo = nullptr; + std::function scheduledFunction = nullptr; }; -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); void detachFunctionalInterrupt(uint8_t pin); -#endif //INTERRUPTS_H +#endif //CORE_FUNCTIONALINTERRUPT_H diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp b/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp deleted file mode 100644 index 17006b9ac9b..00000000000 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupts.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "FunctionalInterrupts.h" -#include - -void ICACHE_RAM_ATTR interruptFunctional(void* arg) -{ - ArgStructure* localArg = static_cast(arg); - if (localArg->interruptInfo) - { - localArg->interruptInfo->value = digitalRead(localArg->interruptInfo->pin); - localArg->interruptInfo->micro = micros(); - } - if (localArg->functionInfo->reqScheduledFunction) - { - schedule_function( - [reqScheduledFunction = localArg->functionInfo->reqScheduledFunction, - interruptInfo = *localArg->interruptInfo]() - { - reqScheduledFunction(interruptInfo); - }); - } - else if (localArg->functionInfo->reqFunction) - { - localArg->functionInfo->reqFunction(); - } -} - -void cleanupFunctional(void* arg) -{ - ArgStructure* localArg = static_cast(arg); - delete localArg; -} - -void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) -{ - // use the local interrupt routine which takes the ArgStructure as argument - - void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } - - FunctionInfo* fi = new FunctionInfo; - fi->reqFunction = intRoutine; - - ArgStructure* as = new ArgStructure; - as->functionInfo = fi; - - attachInterruptArg(pin, interruptFunctional, as, mode); -} - -void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) -{ - void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } - - InterruptInfo* ii = new InterruptInfo(pin); - - FunctionInfo* fi = new FunctionInfo; - fi->reqScheduledFunction = scheduledIntRoutine; - - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; - - attachInterruptArg(pin, interruptFunctional, as, mode); -} - -void detachFunctionalInterrupt(uint8_t pin) -{ - void* localArg = detachInterruptArg(pin); - if (localArg) - { - cleanupFunctional(localArg); - } -} diff --git a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino b/libraries/ESP32/examples/GPIO/ScheduledInterrupt/ScheduledInterrupt.ino similarity index 73% rename from libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino rename to libraries/ESP32/examples/GPIO/ScheduledInterrupt/ScheduledInterrupt.ino index d221f60acfd..8e67904b259 100644 --- a/libraries/ESP32/examples/GPIO/FunctionalInterrupt/FunctionalInterrupt.ino +++ b/libraries/ESP32/examples/GPIO/ScheduledInterrupt/ScheduledInterrupt.ino @@ -1,5 +1,6 @@ #include -#include "FunctionalInterrupts.h" +#include +#include #if defined(ESP32) #define BUTTON1 16 @@ -17,13 +18,16 @@ class Button { Button(uint8_t reqPin) : PIN(reqPin) { pinMode(PIN, INPUT_PULLUP); // Arduino C API: - attachInterruptArg(PIN, [](void* self) { - static_cast(self)->isr(); - }, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" + //attachInterruptArg(PIN, [](void* self) { + // static_cast(self)->isr(); + //}, this, FALLING); // works on ESP32; fails on ESP8266: "ISR not in IRAM" //attachInterruptArg(PIN, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 // FunctionalInterrupts API: - //attachInterrupt(PIN, [this]() { isr(); }, FALLING); // works on ESP32; works on ESP8266 - //attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { Serial.print("Pin "); Serial.println(ii.pin); isr(); }, FALLING); // works on ESP32; works on ESP8266 + attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { + Serial.print("Pin "); + Serial.println(ii.pin); + isr(); + }, FALLING); // works on ESP32; works on ESP8266 }; ~Button() { detachInterrupt(PIN); @@ -70,7 +74,7 @@ void setup() { schedule_function([]() { Serial.println("Scheduled function"); }); - Serial.println("FunctionalInterrupt test/example"); + Serial.println("ScheduledInterrupt test/example"); button1 = new Button(BUTTON1); button2 = new Button(BUTTON2); @@ -81,6 +85,4 @@ void setup() { void loop() { button1->checkPressed(); button2->checkPressed(); - - run_scheduled_functions(); }