From 2c6ca16ee5e68065236d678840657d2fe3049f66 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 17 Jun 2019 14:00:46 +0200 Subject: [PATCH 1/3] Properly check for "functional" ISRs and expose C-style attachInterruptArg --- cores/esp8266/Arduino.h | 1 + cores/esp8266/FunctionalInterrupt.cpp | 6 +- cores/esp8266/core_esp8266_wiring_digital.cpp | 116 ++++++++++-------- 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 34e5fb8fce..80bf1f6ede 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -218,6 +218,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t pin, void (*)(void), int mode); void detachInterrupt(uint8_t pin); +void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); void preinit(void); void setup(void); diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/cores/esp8266/FunctionalInterrupt.cpp index fa57e217e5..c69f94dd7b 100644 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ b/cores/esp8266/FunctionalInterrupt.cpp @@ -7,7 +7,7 @@ typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtrArg)(void*); // Helper functions for Functional interrupt routines -extern "C" void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void*fp , int mode); +extern "C" void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtr userFunc, void*fp, int mode, bool functional); void ICACHE_RAM_ATTR interruptFunctional(void* arg) @@ -47,7 +47,7 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode as->interruptInfo = ii; as->functionInfo = fi; - __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); + __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true); } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) @@ -61,5 +61,5 @@ void attachScheduledInterrupt(uint8_t pin, std::function sc as->interruptInfo = ii; as->functionInfo = fi; - __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); + __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true); } diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 0a8a7252f1..8c7221250a 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -109,8 +109,9 @@ typedef void (*voidFuncPtrArg)(void*); typedef struct { uint8_t mode; - void (*fn)(void); + voidFuncPtr fn; void * arg; + bool functional; } interrupt_handler_t; //duplicate from functionalInterrupt.h keep in sync @@ -125,11 +126,11 @@ typedef struct { void* functionInfo; } ArgStructure; -static interrupt_handler_t interrupt_handlers[16]; +static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, }; static uint32_t interrupt_reg = 0; -void ICACHE_RAM_ATTR interrupt_handler(void *arg) { - (void) arg; +void ICACHE_RAM_ATTR interrupt_handler(void*) +{ uint32_t status = GPIE; GPIEC = status;//clear them interrupts uint32_t levels = GPI; @@ -144,34 +145,37 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) { if (handler->fn && (handler->mode == CHANGE || (handler->mode & 1) == !!(levels & (1 << i)))) { - // to make ISR compatible to Arduino AVR model where interrupts are disabled - // we disable them before we call the client ISR - uint32_t savedPS = xt_rsil(15); // stop other interrupts - ArgStructure* localArg = (ArgStructure*)handler->arg; - if (localArg && localArg->interruptInfo) - { - localArg->interruptInfo->pin = i; - localArg->interruptInfo->value = __digitalRead(i); - localArg->interruptInfo->micro = micros(); - } - if (handler->arg) - { - ((voidFuncPtrArg)handler->fn)(handler->arg); - } - else - { - handler->fn(); + // to make ISR compatible to Arduino AVR model where interrupts are disabled + // we disable them before we call the client ISR + uint32_t savedPS = xt_rsil(15); // stop other interrupts + if (handler->functional) + { + ArgStructure* localArg = (ArgStructure*)handler->arg; + if (localArg && localArg->interruptInfo) + { + localArg->interruptInfo->pin = i; + localArg->interruptInfo->value = __digitalRead(i); + localArg->interruptInfo->micro = micros(); + } + } + if (handler->arg) + { + ((voidFuncPtrArg)handler->fn)(handler->arg); + } + else + { + handler->fn(); + } + xt_wsr_ps(savedPS); } - xt_wsr_ps(savedPS); - } } ETS_GPIO_INTR_ENABLE(); } extern void cleanupFunctional(void* arg); -extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) { - +extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode, bool functional) +{ // #5780 // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map if ((uint32_t)userFunc >= 0x40200000) @@ -183,14 +187,15 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu if(pin < 16) { ETS_GPIO_INTR_DISABLE(); - interrupt_handler_t *handler = &interrupt_handlers[pin]; + interrupt_handler_t* handler = &interrupt_handlers[pin]; handler->mode = mode; - handler->fn = userFunc; - if (handler->arg) // Clean when new attach without detach - { - cleanupFunctional(handler->arg); - } + handler->fn = (voidFuncPtr)userFunc; + if (handler->functional && handler->arg) // Clean when new attach without detach + { + cleanupFunctional(handler->arg); + } handler->arg = arg; + handler->functional = functional; interrupt_reg |= (1 << pin); GPC(pin) &= ~(0xF << GPCI);//INT mode disabled GPIEC = (1 << pin); //Clear Interrupt for this pin @@ -200,28 +205,38 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu } } -extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode ) +extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) { - __attachInterruptArg (pin, userFunc, 0, mode); + __attachInterruptFunctionalArg(pin, userFunc, arg, mode, false); } -extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { - if(pin < 16) { - ETS_GPIO_INTR_DISABLE(); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - interrupt_reg &= ~(1 << pin); - interrupt_handler_t *handler = &interrupt_handlers[pin]; - handler->mode = 0; - handler->fn = 0; - if (handler->arg) - { - cleanupFunctional(handler->arg); - } - handler->arg = 0; - if (interrupt_reg) - ETS_GPIO_INTR_ENABLE(); - } +extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) +{ + __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false); +} + +extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) +{ + if (pin < 16) + { + ETS_GPIO_INTR_DISABLE(); + GPC(pin) &= ~(0xF << GPCI);//INT mode disabled + GPIEC = (1 << pin); //Clear Interrupt for this pin + interrupt_reg &= ~(1 << pin); + interrupt_handler_t* handler = &interrupt_handlers[pin]; + handler->mode = 0; + handler->fn = 0; + if (handler->functional && handler->arg) + { + cleanupFunctional(handler->arg); + } + handler->arg = 0; + handler->functional = false; + if (interrupt_reg) + { + ETS_GPIO_INTR_ENABLE(); + } + } } void initPins() { @@ -243,6 +258,7 @@ extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pi 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 attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt"))); }; From d0279f26e8f00b3d23b9d48b2568b01bd71bd907 Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Mon, 10 Jun 2019 23:53:05 +0200 Subject: [PATCH 2/3] Add facility that schedules ISRs into loop context instead of running them directly as IRQ handler --- cores/esp8266/Arduino.h | 1 + cores/esp8266/core_esp8266_wiring_digital.cpp | 146 +++++++----------- .../examples/Functional/Functional.ino | 87 +++++++++++ libraries/FunctionalInterrupt/keywords.txt | 13 ++ .../FunctionalInterrupt/library.properties | 10 ++ .../src}/FunctionalInterrupt.cpp | 0 .../src}/FunctionalInterrupt.h | 0 7 files changed, 168 insertions(+), 89 deletions(-) create mode 100644 libraries/FunctionalInterrupt/examples/Functional/Functional.ino create mode 100644 libraries/FunctionalInterrupt/keywords.txt create mode 100644 libraries/FunctionalInterrupt/library.properties rename {cores/esp8266 => libraries/FunctionalInterrupt/src}/FunctionalInterrupt.cpp (100%) rename {cores/esp8266 => libraries/FunctionalInterrupt/src}/FunctionalInterrupt.h (100%) diff --git a/cores/esp8266/Arduino.h b/cores/esp8266/Arduino.h index 80bf1f6ede..2be19b5e22 100644 --- a/cores/esp8266/Arduino.h +++ b/cores/esp8266/Arduino.h @@ -219,6 +219,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); void attachInterrupt(uint8_t pin, void (*)(void), int mode); void detachInterrupt(uint8_t pin); void attachInterruptArg(uint8_t pin, void (*)(void*), void* arg, int mode); +void* detachInterruptArg(uint8_t pin); void preinit(void); void setup(void); diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 8c7221250a..0ac0643be4 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -111,22 +111,9 @@ typedef struct { uint8_t mode; voidFuncPtr fn; void * arg; - bool functional; } interrupt_handler_t; -//duplicate from functionalInterrupt.h keep in sync -typedef struct InterruptInfo { - uint8_t pin; - uint8_t value; - uint32_t micro; -} InterruptInfo; - -typedef struct { - InterruptInfo* interruptInfo; - void* functionInfo; -} ArgStructure; - -static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, }; +static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0}, }; static uint32_t interrupt_reg = 0; void ICACHE_RAM_ATTR interrupt_handler(void*) @@ -145,77 +132,55 @@ void ICACHE_RAM_ATTR interrupt_handler(void*) if (handler->fn && (handler->mode == CHANGE || (handler->mode & 1) == !!(levels & (1 << i)))) { - // to make ISR compatible to Arduino AVR model where interrupts are disabled - // we disable them before we call the client ISR - uint32_t savedPS = xt_rsil(15); // stop other interrupts - if (handler->functional) - { - ArgStructure* localArg = (ArgStructure*)handler->arg; - if (localArg && localArg->interruptInfo) - { - localArg->interruptInfo->pin = i; - localArg->interruptInfo->value = __digitalRead(i); - localArg->interruptInfo->micro = micros(); - } - } - if (handler->arg) - { - ((voidFuncPtrArg)handler->fn)(handler->arg); - } - else - { - handler->fn(); - } - xt_wsr_ps(savedPS); + // to make ISR compatible to Arduino AVR model where interrupts are disabled + // we disable them before we call the client ISR + uint32_t savedPS = xt_rsil(15); // stop other interrupts + if (handler->arg) + { + ((voidFuncPtrArg)handler->fn)(handler->arg); + } + else + { + handler->fn(); } + xt_wsr_ps(savedPS); + } } ETS_GPIO_INTR_ENABLE(); } -extern void cleanupFunctional(void* arg); - -extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode, bool functional) +extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) { - // #5780 - // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map - if ((uint32_t)userFunc >= 0x40200000) - { - // ISR not in IRAM - ::printf((PGM_P)F("ISR not in IRAM!\r\n")); - abort(); - } - - if(pin < 16) { - ETS_GPIO_INTR_DISABLE(); - interrupt_handler_t* handler = &interrupt_handlers[pin]; - handler->mode = mode; - handler->fn = (voidFuncPtr)userFunc; - if (handler->functional && handler->arg) // Clean when new attach without detach + // #5780 + // https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map + if ((uint32_t)userFunc >= 0x40200000) { - cleanupFunctional(handler->arg); + // ISR not in IRAM + ::printf((PGM_P)F("ISR not in IRAM!\r\n")); + abort(); } - handler->arg = arg; - handler->functional = functional; - interrupt_reg |= (1 << pin); - GPC(pin) &= ~(0xF << GPCI);//INT mode disabled - GPIEC = (1 << pin); //Clear Interrupt for this pin - GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode" - ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); - ETS_GPIO_INTR_ENABLE(); - } -} -extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void* arg, int mode) -{ - __attachInterruptFunctionalArg(pin, userFunc, arg, mode, false); + if(pin < 16) { + ETS_GPIO_INTR_DISABLE(); + interrupt_handler_t* handler = &interrupt_handlers[pin]; + handler->mode = mode; + handler->fn = (voidFuncPtr)userFunc; + handler->arg = arg; + interrupt_reg |= (1 << pin); + GPC(pin) &= ~(0xF << GPCI);//INT mode disabled + GPIEC = (1 << pin); //Clear Interrupt for this pin + GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode" + ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg); + ETS_GPIO_INTR_ENABLE(); + } } extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) { - __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, 0, mode, false); + __attachInterruptArg(pin, (voidFuncPtrArg)userFunc, 0, mode); } -extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) +extern void __detachInterrupt(uint8_t pin) { if (pin < 16) { @@ -225,13 +190,8 @@ extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) interrupt_reg &= ~(1 << pin); interrupt_handler_t* handler = &interrupt_handlers[pin]; handler->mode = 0; - handler->fn = 0; - if (handler->functional && handler->arg) - { - cleanupFunctional(handler->arg); - } - handler->arg = 0; - handler->functional = false; + handler->fn = nullptr; + handler->arg = nullptr; if (interrupt_reg) { ETS_GPIO_INTR_ENABLE(); @@ -239,26 +199,34 @@ extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) } } +extern void* __detachInterruptArg(uint8_t pin) +{ + void* arg = (pin < 16) ? interrupt_handlers[pin].arg : nullptr; + __detachInterrupt(pin); + return arg; +} + void initPins() { - //Disable UART interrupts - system_set_os_print(0); - U0IE = 0; - U1IE = 0; + //Disable UART interrupts + system_set_os_print(0); + U0IE = 0; + U1IE = 0; - for (int i = 0; i <= 5; ++i) { - pinMode(i, INPUT); - } - // pins 6-11 are used for the SPI flash interface - for (int i = 12; i <= 16; ++i) { - pinMode(i, INPUT); - } + for (int i = 0; i <= 5; ++i) { + pinMode(i, INPUT); + } + // pins 6-11 are used for the SPI flash interface + for (int i = 12; i <= 16; ++i) { + pinMode(i, INPUT); + } } 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 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 attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void* arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); +extern void* detachInterruptArg(uint8_t pin) __attribute__ ((weak, alias("__detachInterruptArg"))); }; diff --git a/libraries/FunctionalInterrupt/examples/Functional/Functional.ino b/libraries/FunctionalInterrupt/examples/Functional/Functional.ino new file mode 100644 index 0000000000..ec8bf382b5 --- /dev/null +++ b/libraries/FunctionalInterrupt/examples/Functional/Functional.ino @@ -0,0 +1,87 @@ +#include +#include + +#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 { + public: + 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, reinterpret_cast(&isr_static), this, FALLING); // works on ESP32; works on ESP8266 + // FunctionalInterrupts API: + attachScheduledInterrupt(PIN, [this](InterruptInfo ii) { + Serial.print("Pin "); + Serial.println(ii.pin); + isr(); + }, FALLING); // works on ESP32; works on ESP8266 + }; + ~Button() { + // Arduino C API: + //detachInterrupt(PIN); + // FunctionalInterrupt API: + detachFunctionalInterrupt(PIN); + } + +#if defined(ESP8266) + void ICACHE_RAM_ATTR isr() +#elif defined(ESP32) + void IRAM_ATTR isr() +#endif + { + numberKeyPresses += 1; + 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); + pressed = false; + } + } + + private: + const uint8_t PIN; + volatile uint32_t numberKeyPresses = 0; + volatile bool pressed = false; +}; + +Button* button1; +Button* button2; + + +void setup() { + Serial.begin(115200); + Serial.println("FunctionalInterrupt test/example"); + + button1 = new Button(BUTTON1); + button2 = new Button(BUTTON2); + + Serial.println("setup() complete"); +} + +void loop() { + button1->checkPressed(); + button2->checkPressed(); +} diff --git a/libraries/FunctionalInterrupt/keywords.txt b/libraries/FunctionalInterrupt/keywords.txt new file mode 100644 index 0000000000..52423e5f95 --- /dev/null +++ b/libraries/FunctionalInterrupt/keywords.txt @@ -0,0 +1,13 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### + +InterruptInfo KEYWORD1 +ArgStructure KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +attachScheduledInterrupt KEYWORD2 +detachFunctionalInterrupt KEYWORD2 diff --git a/libraries/FunctionalInterrupt/library.properties b/libraries/FunctionalInterrupt/library.properties new file mode 100644 index 0000000000..9738f1e971 --- /dev/null +++ b/libraries/FunctionalInterrupt/library.properties @@ -0,0 +1,10 @@ +name=FunctionalInterrupt +version=1.0 +author=hreintke +maintainer=hreintke +sentence=C++ functional and scheduled interrupt handling +paragraph= +category=Other +url=https://github.com/esp8266/Arduino +architectures=esp8266 +dot_a_linkage=true diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp similarity index 100% rename from cores/esp8266/FunctionalInterrupt.cpp rename to libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp diff --git a/cores/esp8266/FunctionalInterrupt.h b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.h similarity index 100% rename from cores/esp8266/FunctionalInterrupt.h rename to libraries/FunctionalInterrupt/src/FunctionalInterrupt.h From 3cd9bd9ed9db2410f29abe5d3729bf52cff98a5e Mon Sep 17 00:00:00 2001 From: "Dirk O. Kaar" Date: Fri, 21 Jun 2019 13:57:05 +0200 Subject: [PATCH 3/3] Refactor FunctionalInterrupt, undo removal of attachInterrupt() for functional arguments. --- .../examples/Functional/Functional.ino | 18 ++-- .../src/FunctionalInterrupt.cpp | 98 ++++++++++--------- .../src/FunctionalInterrupt.h | 31 ++---- 3 files changed, 67 insertions(+), 80 deletions(-) diff --git a/libraries/FunctionalInterrupt/examples/Functional/Functional.ino b/libraries/FunctionalInterrupt/examples/Functional/Functional.ino index ec8bf382b5..22785a01d1 100644 --- a/libraries/FunctionalInterrupt/examples/Functional/Functional.ino +++ b/libraries/FunctionalInterrupt/examples/Functional/Functional.ino @@ -1,6 +1,10 @@ #include #include +#ifndef IRAM_ATTR +#define IRAM_ATTR ICACHE_RAM_ATTR +#endif + #if defined(ESP32) #define BUTTON1 16 #define BUTTON2 17 @@ -35,22 +39,12 @@ class Button { detachFunctionalInterrupt(PIN); } -#if defined(ESP8266) - void ICACHE_RAM_ATTR isr() -#elif defined(ESP32) - void IRAM_ATTR isr() -#endif - { + void IRAM_ATTR isr() { numberKeyPresses += 1; 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 - { + static void IRAM_ATTR isr_static(Button* const self) { self->isr(); } diff --git a/libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp index c69f94dd7b..fd3fddfb0d 100644 --- a/libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp +++ b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.cpp @@ -1,65 +1,73 @@ -#include +#include "FunctionalInterrupt.h" #include -#include "Arduino.h" +#include -// Duplicate typedefs from core_esp8266_wiring_digital_c -typedef void (*voidFuncPtr)(void); -typedef void (*voidFuncPtrArg)(void*); +namespace { -// Helper functions for Functional interrupt routines -extern "C" void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtr userFunc, void*fp, int mode, bool functional); + struct ArgStructure + { + std::function function = nullptr; + }; + void ICACHE_RAM_ATTR interruptFunctional(void* arg) + { + ArgStructure* localArg = static_cast(arg); + localArg->function(); + } -void ICACHE_RAM_ATTR interruptFunctional(void* arg) -{ - ArgStructure* localArg = (ArgStructure*)arg; - 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; + } -extern "C" -{ - void cleanupFunctional(void* arg) - { - ArgStructure* localArg = (ArgStructure*)arg; - delete (FunctionInfo*)localArg->functionInfo; - delete (InterruptInfo*)localArg->interruptInfo; - delete localArg; - } } void attachInterrupt(uint8_t pin, std::function intRoutine, int mode) { - // use the local interrupt routine which takes the ArgStructure as argument - - InterruptInfo* ii = nullptr; + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - FunctionInfo* fi = new FunctionInfo; - fi->reqFunction = intRoutine; + if (intRoutine) + { + ArgStructure* arg = new ArgStructure; + arg->function = std::move(intRoutine); - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; - - __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true); + attachInterruptArg(pin, interruptFunctional, arg, mode); + } } void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { - InterruptInfo* ii = new InterruptInfo; + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } - FunctionInfo* fi = new FunctionInfo; - fi->reqScheduledFunction = scheduledIntRoutine; + if (scheduledIntRoutine) + { + ArgStructure* arg = new ArgStructure; + arg->function = [scheduledIntRoutine = std::move(scheduledIntRoutine), pin]() + { + InterruptInfo interruptInfo(pin); + interruptInfo.value = digitalRead(pin); + interruptInfo.micro = micros(); + schedule_function([scheduledIntRoutine, interruptInfo]() { scheduledIntRoutine(std::move(interruptInfo)); }); + }; - ArgStructure* as = new ArgStructure; - as->interruptInfo = ii; - as->functionInfo = fi; + attachInterruptArg(pin, interruptFunctional, arg, mode); + } +} - __attachInterruptFunctionalArg(pin, (voidFuncPtr)interruptFunctional, as, mode, true); +void detachFunctionalInterrupt(uint8_t pin) +{ + void* localArg = detachInterruptArg(pin); + if (localArg) + { + cleanupFunctional(localArg); + } } diff --git a/libraries/FunctionalInterrupt/src/FunctionalInterrupt.h b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.h index 968793e499..b51ef93f53 100644 --- a/libraries/FunctionalInterrupt/src/FunctionalInterrupt.h +++ b/libraries/FunctionalInterrupt/src/FunctionalInterrupt.h @@ -1,35 +1,20 @@ #ifndef FUNCTIONALINTERRUPT_H #define FUNCTIONALINTERRUPT_H -#include -#include #include -extern "C" { -#include "c_types.h" -#include "ets_sys.h" -} - // Structures for communication -struct InterruptInfo { - uint8_t pin = 0; - uint8_t value = 0; - uint32_t micro = 0; -}; - -struct FunctionInfo { - std::function reqFunction = nullptr; - std::function reqScheduledFunction = nullptr; -}; - -struct ArgStructure { - InterruptInfo* interruptInfo = nullptr; - FunctionInfo* functionInfo = nullptr; +struct InterruptInfo +{ + InterruptInfo(uint8_t _pin) : pin(_pin) {} + const uint8_t pin; + uint8_t value = 0; + uint32_t micro = 0; }; 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 //FUNCTIONALINTERRUPT_H