From aab493ae888ea9d6bdf677a2ae0b58b0b5d9bec2 Mon Sep 17 00:00:00 2001 From: Matti Airas Date: Tue, 1 Mar 2022 13:09:59 +0200 Subject: [PATCH 1/4] Allow attaching reactions to non-singleton apps --- src/ReactESP.cpp | 55 ++++++++++++++++++++++++++++++++++-------------- src/ReactESP.h | 20 ++++++++---------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/ReactESP.cpp b/src/ReactESP.cpp index d4a3ee0..4569fdf 100644 --- a/src/ReactESP.cpp +++ b/src/ReactESP.cpp @@ -25,9 +25,15 @@ bool TimedReaction::operator<(const TimedReaction& other) { (other.last_trigger_time + other.interval); } -void TimedReaction::add() { ReactESP::app->timed_queue.push(this); } +void TimedReaction::add(ReactESP* app) { + if (app == nullptr) { + Serial.println("Got a null pointer in TimedReaction::add"); + app = ReactESP::app; + } + app->timed_queue.push(this); +} -void TimedReaction::remove() { +void TimedReaction::remove(ReactESP* app) { this->enabled = false; // the object will be deleted when it's popped out of the // timer queue @@ -60,10 +66,19 @@ void RepeatReaction::tick() { ReactESP::app->timed_queue.push(this); } -void UntimedReaction::add() { ReactESP::app->untimed_list.push_front(this); } +void UntimedReaction::add(ReactESP* app) { + if (app == nullptr) { + app = ReactESP::app; + } + app->untimed_list.push_front(this); +} + +void UntimedReaction::remove(ReactESP* app) { + if (app == nullptr) { + app = ReactESP::app; + } -void UntimedReaction::remove() { - ReactESP::app->untimed_list.remove(this); + app->untimed_list.remove(this); delete this; } @@ -84,17 +99,25 @@ void ISRReaction::isr(void* this_ptr) { } #endif -void ISRReaction::add() { +void ISRReaction::add(ReactESP* app) { + if (app == nullptr) { + app = ReactESP::app; + } + #ifdef ESP32 gpio_isr_handler_add((gpio_num_t)pin_number, ISRReaction::isr, (void*)this); #elif defined(ESP8266) attachInterrupt(digitalPinToInterrupt(pin_number), callback, mode); #endif - ReactESP::app->isr_reaction_list.push_front(this); + app->isr_reaction_list.push_front(this); } -void ISRReaction::remove() { - ReactESP::app->isr_reaction_list.remove(this); +void ISRReaction::remove(ReactESP* app) { + if (app == nullptr) { + app = ReactESP::app; + } + + app->isr_reaction_list.remove(this); #ifdef ESP32 gpio_isr_handler_remove((gpio_num_t)pin_number); #elif defined(ESP8266) @@ -144,46 +167,46 @@ void ReactESP::tick() { DelayReaction* ReactESP::onDelay(const uint32_t t, const react_callback cb) { DelayReaction* dre = new DelayReaction(t, cb); - dre->add(); + dre->add(this); return dre; } DelayReaction* ReactESP::onDelayMicros(const uint64_t t, const react_callback cb) { DelayReaction* dre = new DelayReaction(t, cb); - dre->add(); + dre->add(this); return dre; } RepeatReaction* ReactESP::onRepeat(const uint32_t t, const react_callback cb) { RepeatReaction* rre = new RepeatReaction(t, cb); - rre->add(); + rre->add(this); return rre; } RepeatReaction* ReactESP::onRepeatMicros(const uint64_t t, const react_callback cb) { RepeatReaction* rre = new RepeatReaction(t, cb); - rre->add(); + rre->add(this); return rre; } StreamReaction* ReactESP::onAvailable(Stream& stream, const react_callback cb) { StreamReaction* sre = new StreamReaction(stream, cb); - sre->add(); + sre->add(this); return sre; } ISRReaction* ReactESP::onInterrupt(const uint8_t pin_number, int mode, const react_callback cb) { ISRReaction* isrre = new ISRReaction(pin_number, mode, cb); - isrre->add(); + isrre->add(this); return isrre; } TickReaction* ReactESP::onTick(const react_callback cb) { TickReaction* tre = new TickReaction(cb); - tre->add(); + tre->add(this); return tre; } diff --git a/src/ReactESP.h b/src/ReactESP.h index ce5c05e..5e6725b 100644 --- a/src/ReactESP.h +++ b/src/ReactESP.h @@ -36,8 +36,8 @@ class Reaction { */ Reaction(react_callback callback) : callback(callback) {} // FIXME: why do these have to be defined? - virtual void add() = 0; - virtual void remove() = 0; + virtual void add(ReactESP* app = nullptr) = 0; + virtual void remove(ReactESP* app = nullptr) = 0; virtual void tick() = 0; }; @@ -76,8 +76,8 @@ class TimedReaction : public Reaction { virtual ~TimedReaction() {} bool operator<(const TimedReaction& other); - void add(); - void remove(); + void add(ReactESP* app = nullptr) override; + void remove(ReactESP* app = nullptr) override; uint32_t getTriggerTime() { return (last_trigger_time + interval) / 1000; } uint64_t getTriggerTimeMicros() { return (last_trigger_time + interval); } bool isEnabled() { return enabled; } @@ -142,8 +142,8 @@ class UntimedReaction : public Reaction { public: UntimedReaction(const react_callback callback) : Reaction(callback) {} virtual ~UntimedReaction() {} - virtual void add(); - virtual void remove(); + virtual void add(ReactESP* app = nullptr) override; + virtual void remove(ReactESP* app = nullptr) override; virtual void tick() = 0; }; @@ -204,9 +204,7 @@ class ISRReaction : public Reaction { * ICACHE_RAM_ATTR attribute. */ ISRReaction(uint8_t pin_number, int mode, const react_callback callback) - : Reaction(callback), - pin_number(pin_number), - mode(mode) { + : Reaction(callback), pin_number(pin_number), mode(mode) { #ifdef ESP32 gpio_int_type_t intr_type; switch (mode) { @@ -233,8 +231,8 @@ class ISRReaction : public Reaction { #endif } virtual ~ISRReaction() {} - void add(); - void remove(); + void add(ReactESP* app = nullptr) override; + void remove(ReactESP* app = nullptr) override; void tick() {} }; From 998f486f7d84bc358181550432e180dfe825feb1 Mon Sep 17 00:00:00 2001 From: Matti Airas Date: Tue, 1 Mar 2022 18:22:12 +0200 Subject: [PATCH 2/4] Enable constructing non-singleton ReactESP apps --- src/ReactESP.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ReactESP.h b/src/ReactESP.h index 5e6725b..1490e23 100644 --- a/src/ReactESP.h +++ b/src/ReactESP.h @@ -251,9 +251,15 @@ class ReactESP { public: /** - * @brief Construct a new ReactESP object + * @brief Construct a new ReactESP object. + * + * @param singleton If true, set the singleton instance to this object */ - ReactESP() { app = this; } + ReactESP(bool singleton = true) { + if (singleton) { + app = this; + } + } void tick(void); /// Static singleton reference to the instantiated ReactESP object From 3b313613a2b3a01de22f98ccdf913077390eed5d Mon Sep 17 00:00:00 2001 From: Matti Airas Date: Tue, 1 Mar 2022 18:22:46 +0200 Subject: [PATCH 3/4] Store the ReactESP app context in TimedReaction --- src/ReactESP.cpp | 3 ++- src/ReactESP.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ReactESP.cpp b/src/ReactESP.cpp index 4569fdf..870d804 100644 --- a/src/ReactESP.cpp +++ b/src/ReactESP.cpp @@ -30,6 +30,7 @@ void TimedReaction::add(ReactESP* app) { Serial.println("Got a null pointer in TimedReaction::add"); app = ReactESP::app; } + app_context = app; app->timed_queue.push(this); } @@ -63,7 +64,7 @@ void RepeatReaction::tick() { this->last_trigger_time = now; } this->callback(); - ReactESP::app->timed_queue.push(this); + app_context->timed_queue.push(this); } void UntimedReaction::add(ReactESP* app) { diff --git a/src/ReactESP.h b/src/ReactESP.h index 1490e23..0f4d2fb 100644 --- a/src/ReactESP.h +++ b/src/ReactESP.h @@ -49,6 +49,8 @@ class TimedReaction : public Reaction { const uint64_t interval; uint64_t last_trigger_time; bool enabled; + // A repeat reaction needs to know which app it belongs to + ReactESP* app_context = nullptr; public: /** From 8cea2a71ff2d748c083862ba17034bc28b8ba266 Mon Sep 17 00:00:00 2001 From: Matti Airas Date: Tue, 1 Mar 2022 18:23:32 +0200 Subject: [PATCH 4/4] Add a ReactESP::remove method --- src/ReactESP.cpp | 4 ++++ src/ReactESP.h | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ReactESP.cpp b/src/ReactESP.cpp index 870d804..3c55b0f 100644 --- a/src/ReactESP.cpp +++ b/src/ReactESP.cpp @@ -211,4 +211,8 @@ TickReaction* ReactESP::onTick(const react_callback cb) { return tre; } +void ReactESP::remove(Reaction* reaction) { + reaction->remove(this); +} + } // namespace reactesp diff --git a/src/ReactESP.h b/src/ReactESP.h index 0f4d2fb..01e56e9 100644 --- a/src/ReactESP.h +++ b/src/ReactESP.h @@ -195,7 +195,7 @@ class ISRReaction : public Reaction { static bool isr_service_installed; static void isr(void* arg); #endif - + public: /** * @brief Construct a new ISRReaction object @@ -327,6 +327,13 @@ class ReactESP { */ TickReaction* onTick(const react_callback cb); + /** + * @brief Remove a reaction from the list of active reactions + * + * @param reaction Reaction to remove + */ + void remove(Reaction* reaction); + private: std::priority_queue, TriggerTimeCompare>