From 734fd04acc4f7b91bdd7fe4e810d9bf8f52a7053 Mon Sep 17 00:00:00 2001 From: hreintke Date: Thu, 5 Apr 2018 15:41:13 +0200 Subject: [PATCH 1/6] Scheduled Interrupt --- cores/esp8266/FunctionalInterrupt.cpp | 56 ++++++++++++++++++--- cores/esp8266/FunctionalInterrupt.h | 20 ++++++++ cores/esp8266/core_esp8266_wiring_digital.c | 26 +++++++++- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/cores/esp8266/FunctionalInterrupt.cpp index b7c7dd1434..70c80e8152 100644 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ b/cores/esp8266/FunctionalInterrupt.cpp @@ -1,24 +1,66 @@ #include - +#include +#include "Arduino.h" // Duplicate typedefs from core_esp8266_wiring_digital_c 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); -// Structure for communication -struct ArgStructure { - std::function reqFunction; -}; void interruptFunctional(void* arg) { - ((ArgStructure*)arg)->reqFunction(); + 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(); + } +} + +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 - __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, new ArgStructure{intRoutine}, mode); + + InterruptInfo* ii = nullptr; + + FunctionInfo* fi = new FunctionInfo; + fi->reqFunction = intRoutine; + + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; + + __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); +} + +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) +{ + + InterruptInfo* ii = new InterruptInfo; + + FunctionInfo* fi = new FunctionInfo; + fi->reqScheduledFunction = scheduledIntRoutine; + + ArgStructure* as = new ArgStructure; + as->interruptInfo = ii; + as->functionInfo = fi; + + __attachInterruptArg (pin, (voidFuncPtr)interruptFunctional, as, mode); } diff --git a/cores/esp8266/FunctionalInterrupt.h b/cores/esp8266/FunctionalInterrupt.h index fedc20ad68..968793e499 100644 --- a/cores/esp8266/FunctionalInterrupt.h +++ b/cores/esp8266/FunctionalInterrupt.h @@ -10,6 +10,26 @@ extern "C" { #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; +}; + void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); +void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); + #endif //INTERRUPTS_H diff --git a/cores/esp8266/core_esp8266_wiring_digital.c b/cores/esp8266/core_esp8266_wiring_digital.c index 9d88ba847e..18692027b3 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.c +++ b/cores/esp8266/core_esp8266_wiring_digital.c @@ -113,6 +113,17 @@ typedef struct { void * arg; } 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]; static uint32_t interrupt_reg = 0; @@ -135,7 +146,14 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) { (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 + uint32_t savedPS = xt_rsil(15); // stop other interrupts + ArgStructure* localArg = (ArgStructure*)handler->arg; + if (localArg->interruptInfo) + { + localArg->interruptInfo->pin = i; + localArg->interruptInfo->value = __digitalRead(i); + localArg->interruptInfo->micro = micros(); + } if (handler->arg) { ((voidFuncPtrArg)handler->fn)(handler->arg); @@ -170,6 +188,8 @@ extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, __attachInterruptArg (pin, userFunc, 0, mode); } +extern void cleanupFunctional(void* arg); + extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { if(pin < 16) { ETS_GPIO_INTR_DISABLE(); @@ -179,6 +199,10 @@ extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { interrupt_handler_t *handler = &interrupt_handlers[pin]; handler->mode = 0; handler->fn = 0; + if (handler->arg) + { + cleanupFunctional(handler->arg); + } handler->arg = 0; ETS_GPIO_INTR_ENABLE(); } From 24a0b2f34e5b5ab828038c1308262ba63af3266f Mon Sep 17 00:00:00 2001 From: hreintke Date: Thu, 5 Apr 2018 16:06:16 +0200 Subject: [PATCH 2/6] use capital letter for Schedule.h --- cores/esp8266/FunctionalInterrupt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/cores/esp8266/FunctionalInterrupt.cpp index 70c80e8152..e4a54658ff 100644 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ b/cores/esp8266/FunctionalInterrupt.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "Arduino.h" // Duplicate typedefs from core_esp8266_wiring_digital_c From ea39a178b4d3cb41f633d5e7538e73da99ac7ae3 Mon Sep 17 00:00:00 2001 From: hreintke Date: Tue, 24 Apr 2018 12:03:24 +0200 Subject: [PATCH 3/6] Prevent memory leak when attach is called multiple times without detach --- cores/esp8266/core_esp8266_wiring_digital.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cores/esp8266/core_esp8266_wiring_digital.c b/cores/esp8266/core_esp8266_wiring_digital.c index 18692027b3..8912d23c74 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.c +++ b/cores/esp8266/core_esp8266_wiring_digital.c @@ -174,6 +174,10 @@ extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFu 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->arg = arg; interrupt_reg |= (1 << pin); GPC(pin) &= ~(0xF << GPCI);//INT mode disabled From d5f0263bdf6ef54e1efb9f39dc40cc51a0b29efa Mon Sep 17 00:00:00 2001 From: hreintke Date: Sun, 29 Apr 2018 18:05:09 +0200 Subject: [PATCH 4/6] Add improved schedule_function --- cores/esp8266/ScheduledFunctions.cpp | 117 +++++++++++++++++++++++++++ cores/esp8266/ScheduledFunctions.h | 50 ++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 cores/esp8266/ScheduledFunctions.cpp create mode 100644 cores/esp8266/ScheduledFunctions.h diff --git a/cores/esp8266/ScheduledFunctions.cpp b/cores/esp8266/ScheduledFunctions.cpp new file mode 100644 index 0000000000..2eb59d3066 --- /dev/null +++ b/cores/esp8266/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({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({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 = 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/cores/esp8266/ScheduledFunctions.h b/cores/esp8266/ScheduledFunctions.h new file mode 100644 index 0000000000..03fc6f412f --- /dev/null +++ b/cores/esp8266/ScheduledFunctions.h @@ -0,0 +1,50 @@ +/* + * 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 + { + 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); + void runScheduledFunctions(); + void removeFunction(ScheduledRegistration sr); + + + static std::list scheduledFunctions; + unsigned int maxElements; + unsigned int countElements = 0; + +}; + +#endif /* SCHEDULEDFUNCTIONS_H_ */ From c45e7b9500da4386e27c6b1d0e7d02c77a8f98e9 Mon Sep 17 00:00:00 2001 From: hreintke Date: Tue, 1 May 2018 12:51:11 +0200 Subject: [PATCH 5/6] WIP : Integrate FunctionalInterrupt & ScheduledInterrupt --- cores/esp8266/FunctionalInterrupt.cpp | 8 ++++++-- cores/esp8266/FunctionalInterrupt.h | 2 ++ cores/esp8266/ScheduledFunctions.cpp | 6 +++--- cores/esp8266/ScheduledFunctions.h | 3 ++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cores/esp8266/FunctionalInterrupt.cpp b/cores/esp8266/FunctionalInterrupt.cpp index e4a54658ff..84ae8f4289 100644 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ b/cores/esp8266/FunctionalInterrupt.cpp @@ -1,6 +1,7 @@ #include #include #include "Arduino.h" +#include // Duplicate typedefs from core_esp8266_wiring_digital_c typedef void (*voidFuncPtr)(void); @@ -15,7 +16,7 @@ void interruptFunctional(void* arg) ArgStructure* localArg = (ArgStructure*)arg; if (localArg->functionInfo->reqScheduledFunction) { - schedule_function(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo)))); + scheduledInterrupts->scheduleFunctionReg(std::bind(localArg->functionInfo->reqScheduledFunction,InterruptInfo(*(localArg->interruptInfo))), false, true); } if (localArg->functionInfo->reqFunction) { @@ -52,7 +53,10 @@ void attachInterrupt(uint8_t pin, std::function intRoutine, int mode void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode) { - + if (!scheduledInterrupts) + { + scheduledInterrupts = new ScheduledFunctions(32); + } InterruptInfo* ii = new InterruptInfo; FunctionInfo* fi = new FunctionInfo; diff --git a/cores/esp8266/FunctionalInterrupt.h b/cores/esp8266/FunctionalInterrupt.h index 968793e499..a6d53188ae 100644 --- a/cores/esp8266/FunctionalInterrupt.h +++ b/cores/esp8266/FunctionalInterrupt.h @@ -4,6 +4,7 @@ #include #include #include +#include extern "C" { #include "c_types.h" @@ -28,6 +29,7 @@ struct ArgStructure { FunctionInfo* functionInfo = nullptr; }; +static ScheduledFunctions* scheduledInterrupts; void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); diff --git a/cores/esp8266/ScheduledFunctions.cpp b/cores/esp8266/ScheduledFunctions.cpp index 2eb59d3066..25bc58db61 100644 --- a/cores/esp8266/ScheduledFunctions.cpp +++ b/cores/esp8266/ScheduledFunctions.cpp @@ -51,7 +51,7 @@ std::list::iterator ScheduledFunctions::er bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf, bool continuous, bool front) { - return (insertElement({continuous,nullptr,sf}, front) == nullptr); + return (insertElement({this,continuous,nullptr,sf}, front) == nullptr); } bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) @@ -61,7 +61,7 @@ bool ScheduledFunctions::scheduleFunction(ScheduledFunction sf) ScheduledRegistration ScheduledFunctions::scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front) { - return insertElement({continuous,std::make_shared(1),sf},front); + return insertElement({this,continuous,std::make_shared(1),sf},front); } void ScheduledFunctions::runScheduledFunctions() @@ -88,7 +88,7 @@ void ScheduledFunctions::runScheduledFunctions() } if ((!it->continuous) || (erase)) { - it = eraseElement(it); + it = it->_this->eraseElement(it); } else { diff --git a/cores/esp8266/ScheduledFunctions.h b/cores/esp8266/ScheduledFunctions.h index 03fc6f412f..0129635364 100644 --- a/cores/esp8266/ScheduledFunctions.h +++ b/cores/esp8266/ScheduledFunctions.h @@ -27,6 +27,7 @@ class ScheduledFunctions { struct ScheduledElement { + ScheduledFunctions* _this; bool continuous; ScheduledRegistration registration; ScheduledFunction function; @@ -37,7 +38,7 @@ class ScheduledFunctions { bool scheduleFunction(ScheduledFunction sf, bool continuous, bool front); bool scheduleFunction(ScheduledFunction sf); ScheduledRegistration scheduleFunctionReg (ScheduledFunction sf, bool continuous, bool front); - void runScheduledFunctions(); + static void runScheduledFunctions(); void removeFunction(ScheduledRegistration sr); From ff8c892e68cc60ed760224b8d16d24226da5363a Mon Sep 17 00:00:00 2001 From: hreintke Date: Mon, 18 Jun 2018 09:05:45 +0200 Subject: [PATCH 6/6] Fix travis error --- cores/esp8266/core_esp8266_wiring_digital.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp8266/core_esp8266_wiring_digital.c b/cores/esp8266/core_esp8266_wiring_digital.c index ebd37c0eca..a9f09a9e5e 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.c +++ b/cores/esp8266/core_esp8266_wiring_digital.c @@ -168,6 +168,8 @@ void ICACHE_RAM_ATTR interrupt_handler(void *arg) { ETS_GPIO_INTR_ENABLE(); } +extern void cleanupFunctional(void* arg); + extern void ICACHE_RAM_ATTR __attachInterruptArg(uint8_t pin, voidFuncPtr userFunc, void *arg, int mode) { if(pin < 16) { ETS_GPIO_INTR_DISABLE(); @@ -193,8 +195,6 @@ extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, __attachInterruptArg (pin, userFunc, 0, mode); } -extern void cleanupFunctional(void* arg); - extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) { if(pin < 16) { ETS_GPIO_INTR_DISABLE();