diff --git a/cores/esp8266/core_esp8266_main.cpp b/cores/esp8266/core_esp8266_main.cpp index 61c07da909..23afc9c483 100644 --- a/cores/esp8266/core_esp8266_main.cpp +++ b/cores/esp8266/core_esp8266_main.cpp @@ -23,7 +23,6 @@ //This may be used to change user task stack size: //#define CONT_STACKSIZE 4096 #include -#include "Schedule.h" extern "C" { #include "ets_sys.h" #include "os_type.h" @@ -40,7 +39,6 @@ extern "C" { #define OPTIMISTIC_YIELD_TIME_US 16000 extern "C" void call_user_start(); -extern void loop(); extern void setup(); extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); @@ -90,19 +88,15 @@ void preloop_update_frequency() { #endif } - -static inline void esp_yield_within_cont() __attribute__((always_inline)); -static void esp_yield_within_cont() { - cont_yield(g_pcont); - run_scheduled_recurrent_functions(); -} - -extern "C" void esp_yield() { +extern "C" void __esp_yield() __attribute__((weak)); +extern "C" void __esp_yield() { if (cont_can_yield(g_pcont)) { - esp_yield_within_cont(); + cont_yield(g_pcont); } } +extern "C" void esp_yield(void) __attribute__ ((weak, alias("__esp_yield"))); + extern "C" void esp_schedule() { // always on CONT stack here ets_post(LOOP_TASK_PRIORITY, 0, 0); @@ -111,7 +105,7 @@ extern "C" void esp_schedule() { extern "C" void __yield() { if (cont_can_yield(g_pcont)) { esp_schedule(); - esp_yield_within_cont(); + esp_yield(); } else { panic(); @@ -157,14 +151,11 @@ extern "C" bool IRAM_ATTR ets_post(uint8 prio, ETSSignal sig, ETSParam par) { return rc; } -extern "C" void __loop_end (void) -{ - run_scheduled_functions(); - run_scheduled_recurrent_functions(); +extern "C" void esp_loop(void) __attribute__((weak)); +extern "C" void esp_loop(void) { + loop(); } -extern "C" void loop_end (void) __attribute__ ((weak, alias("__loop_end"))); - static void loop_wrapper() { static bool setup_done = false; preloop_update_frequency(); @@ -172,8 +163,7 @@ static void loop_wrapper() { setup(); setup_done = true; } - loop(); - loop_end(); + esp_loop(); esp_schedule(); } diff --git a/cores/esp8266/core_esp8266_wiring_digital.cpp b/cores/esp8266/core_esp8266_wiring_digital.cpp index 5ed0a40ab7..21568879e0 100644 --- a/cores/esp8266/core_esp8266_wiring_digital.cpp +++ b/cores/esp8266/core_esp8266_wiring_digital.cpp @@ -115,16 +115,21 @@ typedef struct { bool functional; } interrupt_handler_t; -//duplicate from functionalInterrupt.h keep in sync +//duplicates from functionalInterrupt.h keep in sync typedef struct InterruptInfo { uint8_t pin; uint8_t value; uint32_t micro; } InterruptInfo; -typedef struct { +typedef struct FunctionInfo { + std::function reqFunction; + std::function reqScheduledFunction; +} FunctionInfo; + +typedef struct ArgStructure { InterruptInfo* interruptInfo; - void* functionInfo; + FunctionInfo* functionInfo; } ArgStructure; static interrupt_handler_t interrupt_handlers[16] = { {0, 0, 0, 0}, }; @@ -172,7 +177,13 @@ void ICACHE_RAM_ATTR interrupt_handler(void*) ETS_GPIO_INTR_ENABLE(); } -extern void cleanupFunctional(void* arg); +static void cleanupFunctional(void* arg) +{ + ArgStructure* localArg = (ArgStructure*)arg; + delete localArg->interruptInfo; + delete localArg->functionInfo; + delete localArg; +} static void set_interrupt_handlers(uint8_t pin, voidFuncPtr userFunc, void* arg, uint8_t mode, bool functional) { diff --git a/libraries/Schedule/library.properties b/libraries/Schedule/library.properties new file mode 100644 index 0000000000..b9153597be --- /dev/null +++ b/libraries/Schedule/library.properties @@ -0,0 +1,10 @@ +name=Schedule +version=1.0 +author=Ivan Grokhotkov (ivan@esp8266.com) +maintainer=Ivan Grokhotkov (ivan@esp8266.com) +sentence= +paragraph= +category=Other +url=https://github.com/esp8266/Arduino +architectures=esp8266 +dot_a_linkage=true diff --git a/cores/esp8266/Schedule.cpp b/libraries/Schedule/src/Schedule.cpp similarity index 91% rename from cores/esp8266/Schedule.cpp rename to libraries/Schedule/src/Schedule.cpp index ed39736e55..3112ecb485 100644 --- a/cores/esp8266/Schedule.cpp +++ b/libraries/Schedule/src/Schedule.cpp @@ -2,9 +2,27 @@ #include #include "Schedule.h" -#include "PolledTimeout.h" -#include "interrupts.h" -#include "coredecls.h" +#include +#include +#include + +extern "C" +{ + void esp_loop() + { + loop(); + run_scheduled_functions(); + run_scheduled_recurrent_functions(); + } + + void __esp_yield(); + + extern "C" void esp_yield() + { + __esp_yield(); + run_scheduled_recurrent_functions(); + } +} typedef std::function mSchedFuncT; struct scheduled_fn_t @@ -120,7 +138,7 @@ void run_scheduled_functions () if (yieldNow) { - // because scheduled function are allowed to last: + // because scheduled functions are allowed to last: // this is yield() in cont stack: esp_schedule(); cont_yield(g_pcont); diff --git a/cores/esp8266/Schedule.h b/libraries/Schedule/src/Schedule.h similarity index 100% rename from cores/esp8266/Schedule.h rename to libraries/Schedule/src/Schedule.h diff --git a/libraries/ScheduledInterrupts/examples/Functional/Functional.ino b/libraries/ScheduledInterrupts/examples/Functional/Functional.ino new file mode 100644 index 0000000000..0461ef2879 --- /dev/null +++ b/libraries/ScheduledInterrupts/examples/Functional/Functional.ino @@ -0,0 +1,69 @@ +#include + +#ifndef IRAM_ATTR +#define IRAM_ATTR ICACHE_RAM_ATTR +#endif + +#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(const uint8_t reqPin) : _PIN(reqPin) { + pinMode(_PIN, INPUT_PULLUP); + attachInterrupt(_PIN, std::bind(&Button::buttonIsr, this), FALLING); + }; + ~Button() { + detachInterrupt(_PIN); + } + + void IRAM_ATTR buttonIsr() { + _numberKeyPresses += 1; + _pressed = true; + } + + uint32_t testResetPressed() { + if (_pressed) { + Serial.printf("Button on pin %u has been pressed %u times\n", _PIN, _numberKeyPresses); + _pressed = false; + } + return _numberKeyPresses; + } + + private: + const uint8_t _PIN; + volatile uint32_t _numberKeyPresses = 0; + volatile bool _pressed = false; +}; + +// Pointers and "new" in setup() are used in this example to simply test +// and demonstrate how an ISR object can be constructed and destructed at runtime, +// including the detach of the ISR from the GPIO. +Button* button1 = nullptr; +Button* button2 = nullptr; + +void setup() { + Serial.begin(115200); + Serial.println("ScheduledInterrupts test/example"); + + button1 = new Button(BUTTON1); + button2 = new Button(BUTTON2); + + Serial.println("setup() complete"); +} + +void loop() { + button1->testResetPressed(); + if (nullptr != button2 && 10 < button2->testResetPressed()) { + delete button2; + button2 = nullptr; + } +} diff --git a/libraries/ScheduledInterrupts/examples/ScheduledFunctional/ScheduledFunctional.ino b/libraries/ScheduledInterrupts/examples/ScheduledFunctional/ScheduledFunctional.ino new file mode 100644 index 0000000000..6d21a01c1e --- /dev/null +++ b/libraries/ScheduledInterrupts/examples/ScheduledFunctional/ScheduledFunctional.ino @@ -0,0 +1,74 @@ +#include + +#ifndef IRAM_ATTR +#define IRAM_ATTR ICACHE_RAM_ATTR +#endif + +#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(const uint8_t reqPin) : _PIN(reqPin) { + pinMode(_PIN, INPUT_PULLUP); + attachScheduledInterrupt(_PIN, [this](const InterruptInfo & ii) { + Serial.print("Pin "); + Serial.println(ii.pin); + buttonIsr(); + }, FALLING); // works on ESP8266 + }; + ~Button() { + detachInterrupt(_PIN); + } + + void IRAM_ATTR buttonIsr() { + _numberKeyPresses += 1; + _pressed = true; + } + + uint32_t testResetPressed() { + if (_pressed) { + Serial.printf("Button on pin %u has been pressed %u times\n", _PIN, _numberKeyPresses); + _pressed = false; + } + return _numberKeyPresses; + } + + private: + const uint8_t _PIN; + volatile uint32_t _numberKeyPresses = 0; + volatile bool _pressed = false; +}; + +// Pointers and "new" in setup() are used in this example to simply test +// and demonstrate how an ISR object can be constructed and destructed at runtime, +// including the detach of the ISR from the GPIO. +Button* button1; +Button* button2; + + +void setup() { + Serial.begin(115200); + Serial.println("ScheduledInterrupts test/example"); + + button1 = new Button(BUTTON1); + button2 = new Button(BUTTON2); + + Serial.println("setup() complete"); +} + +void loop() { + button1->testResetPressed(); + if (nullptr != button2 && 10 < button2->testResetPressed()) { + delete button2; + button2 = nullptr; + } +} diff --git a/libraries/ScheduledInterrupts/keywords.txt b/libraries/ScheduledInterrupts/keywords.txt new file mode 100644 index 0000000000..b8c0fc83f1 --- /dev/null +++ b/libraries/ScheduledInterrupts/keywords.txt @@ -0,0 +1,13 @@ +####################################### +# Datatypes (KEYWORD1) +####################################### + +InterruptInfo KEYWORD1 +ArgStructure KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +attachInterrupt KEYWORD2 +attachScheduledInterrupt KEYWORD2 diff --git a/libraries/ScheduledInterrupts/library.properties b/libraries/ScheduledInterrupts/library.properties new file mode 100644 index 0000000000..e47c0faa4a --- /dev/null +++ b/libraries/ScheduledInterrupts/library.properties @@ -0,0 +1,10 @@ +name=ScheduledInterrupts +version=1.0 +author=hreintke +maintainer=hreintke +sentence=C++ functional, 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/ScheduledInterrupts/src/ScheduledInterrupts.cpp similarity index 84% rename from cores/esp8266/FunctionalInterrupt.cpp rename to libraries/ScheduledInterrupts/src/ScheduledInterrupts.cpp index 665d8043b3..d583b48be0 100644 --- a/cores/esp8266/FunctionalInterrupt.cpp +++ b/libraries/ScheduledInterrupts/src/ScheduledInterrupts.cpp @@ -1,6 +1,6 @@ -#include +#include "ScheduledInterrupts.h" #include -#include "Arduino.h" +#include // Duplicate typedefs from core_esp8266_wiring_digital_c typedef void (*voidFuncPtr)(void); @@ -23,17 +23,6 @@ void ICACHE_RAM_ATTR interruptFunctional(void* arg) } } -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 diff --git a/cores/esp8266/FunctionalInterrupt.h b/libraries/ScheduledInterrupts/src/ScheduledInterrupts.h similarity index 88% rename from cores/esp8266/FunctionalInterrupt.h rename to libraries/ScheduledInterrupts/src/ScheduledInterrupts.h index 968793e499..c192fd212e 100644 --- a/cores/esp8266/FunctionalInterrupt.h +++ b/libraries/ScheduledInterrupts/src/ScheduledInterrupts.h @@ -1,5 +1,5 @@ -#ifndef FUNCTIONALINTERRUPT_H -#define FUNCTIONALINTERRUPT_H +#ifndef SCHEDULEDINTERRUPTS_H +#define SCHEDULEDINTERRUPTS_H #include #include @@ -31,5 +31,4 @@ struct ArgStructure { void attachInterrupt(uint8_t pin, std::function intRoutine, int mode); void attachScheduledInterrupt(uint8_t pin, std::function scheduledIntRoutine, int mode); - -#endif //INTERRUPTS_H +#endif // SCHEDULEDINTERRUPTS_H diff --git a/libraries/Ticker/examples/Blinker/Blinker.ino b/libraries/Ticker/examples/Blinker/Blinker.ino new file mode 100644 index 0000000000..ce5a18a316 --- /dev/null +++ b/libraries/Ticker/examples/Blinker/Blinker.ino @@ -0,0 +1,41 @@ +#include +#include + +// attach a LED to pPIO 21 +#define LED_PIN 21 + +Ticker blinker; +Ticker toggler; +Ticker changer; +float blinkerPace = 0.1; //seconds +const float togglePeriod = 5; //seconds + +void change() { + blinkerPace = 0.5; +} + +void blink() { + digitalWrite(LED_PIN, !digitalRead(LED_PIN)); +} + +void toggle() { + static bool isBlinking = false; + if (isBlinking) { + blinker.detach(); + isBlinking = false; + } else { + blinker.attach(blinkerPace, blink); + isBlinking = true; + } + digitalWrite(LED_PIN, LOW); //make sure LED on on after toggling (pin LOW = led ON) +} + +void setup() { + pinMode(LED_PIN, OUTPUT); + toggler.attach(togglePeriod, toggle); + changer.once(30, change); +} + +void loop() { + +} diff --git a/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino b/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino index 33c9435982..387e6d6bcb 100644 --- a/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino +++ b/libraries/Ticker/examples/TickerFunctional/TickerFunctional.ino @@ -1,5 +1,5 @@ -#include "Arduino.h" -#include "Ticker.h" +#include +#include #define LED1 2 #define LED2 4 diff --git a/libraries/Ticker/keywords.txt b/libraries/Ticker/keywords.txt index 1ecd8d0eda..b1020c4e59 100644 --- a/libraries/Ticker/keywords.txt +++ b/libraries/Ticker/keywords.txt @@ -1,29 +1,21 @@ -####################################### -# Syntax Coloring Map For Wire -####################################### - ####################################### # Datatypes (KEYWORD1) ####################################### +Ticker KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### +attach_scheduled KEYWORD2 attach KEYWORD2 +attach_ms_scheduled KEYWORD2 attach_ms KEYWORD2 +once_scheduled KEYWORD2 once KEYWORD2 +once_ms_scheduled KEYWORD2 once_ms KEYWORD2 detach KEYWORD2 active KEYWORD2 -####################################### -# Instances (KEYWORD2) -####################################### - -Ticker KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - diff --git a/libraries/Ticker/Ticker.cpp b/libraries/Ticker/src/Ticker.cpp similarity index 100% rename from libraries/Ticker/Ticker.cpp rename to libraries/Ticker/src/Ticker.cpp diff --git a/libraries/Ticker/Ticker.h b/libraries/Ticker/src/Ticker.h similarity index 100% rename from libraries/Ticker/Ticker.h rename to libraries/Ticker/src/Ticker.h diff --git a/tests/host/Makefile b/tests/host/Makefile index aaf8a88d91..1159d7d0b6 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -67,7 +67,7 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ spiffs/spiffs_nucleus.cpp \ libb64/cencode.cpp \ libb64/cdecode.cpp \ - Schedule.cpp \ + ../../libraries/Schedule/src/Schedule.cpp \ HardwareSerial.cpp \ crc32.cpp \ ) \ diff --git a/tests/host/common/Arduino.cpp b/tests/host/common/Arduino.cpp index 5192028e73..93aa923264 100644 --- a/tests/host/common/Arduino.cpp +++ b/tests/host/common/Arduino.cpp @@ -42,7 +42,7 @@ extern "C" void optimistic_yield (uint32_t interval_us) usleep(interval_us); } -extern "C" void esp_yield() +extern "C" void __esp_yield() { }