diff --git a/code/espurna/sensors/BaseSensor.h b/code/espurna/sensors/BaseSensor.h index f0e18d37..30c069c0 100644 --- a/code/espurna/sensors/BaseSensor.h +++ b/code/espurna/sensors/BaseSensor.h @@ -123,20 +123,6 @@ class BaseSensor { } - // Interrupt attach callback - void attached(unsigned char gpio) { - #if SENSOR_DEBUG - DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, description().c_str()); - #endif - } - - // Interrupt detach callback - void detached(unsigned char gpio) { - #if SENSOR_DEBUG - DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, description().c_str()); - #endif - } - // Return sensor status (true for ready) bool status() { return _error == 0; } @@ -146,16 +132,14 @@ class BaseSensor { // Number of available slots unsigned char count() { return _count; } - // Handle interrupt calls - void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) {} - protected: - // Attach interrupt - void attach(BaseSensor * instance, unsigned char gpio, unsigned char mode); - - // Detach interrupt - void detach(unsigned char gpio); + // Check if valid GPIO + bool _validGPIO(unsigned char gpio) { + if (0 <= gpio && gpio <= 5) return true; + if (12 <= gpio && gpio <= 15) return true; + return false; + } unsigned char _sensor_id = 0x00; int _error = 0; @@ -167,53 +151,3 @@ class BaseSensor { unsigned char _address = 0; }; - -// ----------------------------------------------------------------------------- -// Interrupt helpers -// ----------------------------------------------------------------------------- - -BaseSensor * _isr_sensor_instance[16] = {NULL}; - -void ICACHE_RAM_ATTR _sensor_isr(unsigned char gpio) { - if (_isr_sensor_instance[gpio]) { - _isr_sensor_instance[gpio]->handleInterrupt(gpio); - } -} - -void ICACHE_RAM_ATTR _sensor_isr_0() { _sensor_isr(0); } -void ICACHE_RAM_ATTR _sensor_isr_1() { _sensor_isr(1); } -void ICACHE_RAM_ATTR _sensor_isr_2() { _sensor_isr(2); } -void ICACHE_RAM_ATTR _sensor_isr_3() { _sensor_isr(3); } -void ICACHE_RAM_ATTR _sensor_isr_4() { _sensor_isr(4); } -void ICACHE_RAM_ATTR _sensor_isr_5() { _sensor_isr(5); } -void ICACHE_RAM_ATTR _sensor_isr_12() { _sensor_isr(12); } -void ICACHE_RAM_ATTR _sensor_isr_13() { _sensor_isr(13); } -void ICACHE_RAM_ATTR _sensor_isr_14() { _sensor_isr(14); } -void ICACHE_RAM_ATTR _sensor_isr_15() { _sensor_isr(15); } - -static void (*_sensor_isrs[16])() = { - _sensor_isr_0, _sensor_isr_1, _sensor_isr_2, _sensor_isr_3, _sensor_isr_4, _sensor_isr_5, - NULL, NULL, NULL, NULL, NULL, NULL, - _sensor_isr_12, _sensor_isr_13, _sensor_isr_14, _sensor_isr_15 -}; - -void BaseSensor::attach(BaseSensor * instance, unsigned char gpio, unsigned char mode) { - if ((6 <= gpio) && (gpio <=11)) return; - if (gpio >= 16) return; - detach(gpio); - if (_sensor_isrs[gpio]) { - _isr_sensor_instance[gpio] = instance; - attachInterrupt(gpio, _sensor_isrs[gpio], mode); - instance->attached(gpio); - } -} - -void BaseSensor::detach(unsigned char gpio) { - if ((6 <= gpio) && (gpio <=11)) return; - if (gpio >= 16) return; - if (_isr_sensor_instance[gpio]) { - detachInterrupt(gpio); - _isr_sensor_instance[gpio]->detached(gpio); - _isr_sensor_instance[gpio] = NULL; - } -} diff --git a/code/espurna/sensors/ECH1560Sensor.h b/code/espurna/sensors/ECH1560Sensor.h index bb13bfac..63403069 100644 --- a/code/espurna/sensors/ECH1560Sensor.h +++ b/code/espurna/sensors/ECH1560Sensor.h @@ -22,7 +22,7 @@ class ECH1560Sensor : public BaseSensor { } ~ECH1560Sensor() { - if (_interrupt_gpio != GPIO_NONE) detach(_interrupt_gpio); + _enableInterrupts(false); } // --------------------------------------------------------------------- @@ -69,27 +69,10 @@ class ECH1560Sensor : public BaseSensor { pinMode(_clk, INPUT); pinMode(_miso, INPUT); - if (_interrupt_gpio != GPIO_NONE) detach(_interrupt_gpio); - attach(this, _clk, RISING); + _enableInterrupts(true); } - // Interrupt attach callback - void attached(unsigned char gpio) { - BaseSensor::attached(gpio); - _interrupt_gpio = gpio; - } - - // Interrupt detach callback - void detached(unsigned char gpio) { - BaseSensor::detached(gpio); - if (_interrupt_gpio == gpio) _interrupt_gpio = GPIO_NONE; - } - - void ICACHE_RAM_ATTR handleInterrupt() { - _isr(); - } - // Descriptive name of the sensor String description() { char buffer[25]; @@ -117,13 +100,9 @@ class ECH1560Sensor : public BaseSensor { return 0; } - protected: + void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) { - // --------------------------------------------------------------------- - // Protected - // --------------------------------------------------------------------- - - void ICACHE_RAM_ATTR _isr() { + (void) gpio; // if we are trying to find the sync-time (CLK goes high for 1-2ms) if (_dosync == false) { @@ -152,6 +131,36 @@ class ECH1560Sensor : public BaseSensor { } + protected: + + // --------------------------------------------------------------------- + // Interrupt management + // --------------------------------------------------------------------- + + void _attach(ECH1560Sensor * instance, unsigned char gpio, unsigned char mode); + void _detach(unsigned char gpio); + + void _enableInterrupts(bool value) { + + static unsigned char _interrupt_clk = GPIO_NONE; + + if (value) { + if (_interrupt_clk != _clk) { + if (_interrupt_clk != GPIO_NONE) _detach(_interrupt_clk); + _attach(this, _clk, RISING); + _interrupt_clk = _clk; + } + } else if (_interrupt_clk != GPIO_NONE) { + _detach(_interrupt_clk); + _interrupt_clk = GPIO_NONE; + } + + } + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + void _sync() { unsigned int byte1 = 0; @@ -247,7 +256,6 @@ class ECH1560Sensor : public BaseSensor { unsigned char _clk = 0; unsigned char _miso = 0; - unsigned char _interrupt_gpio = GPIO_NONE; bool _inverted = false; volatile long _bits_count = 0; @@ -262,3 +270,57 @@ class ECH1560Sensor : public BaseSensor { unsigned char _data[24]; }; + +// ----------------------------------------------------------------------------- +// Interrupt helpers +// ----------------------------------------------------------------------------- + +ECH1560Sensor * _ech1560_sensor_instance[10] = {NULL}; + +void ICACHE_RAM_ATTR _ech1560_sensor_isr(unsigned char gpio) { + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_ech1560_sensor_instance[index]) { + _ech1560_sensor_instance[index]->handleInterrupt(gpio); + } +} + +void ICACHE_RAM_ATTR _ech1560_sensor_isr_0() { _ech1560_sensor_isr(0); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_1() { _ech1560_sensor_isr(1); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_2() { _ech1560_sensor_isr(2); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_3() { _ech1560_sensor_isr(3); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_4() { _ech1560_sensor_isr(4); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_5() { _ech1560_sensor_isr(5); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_12() { _ech1560_sensor_isr(12); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_13() { _ech1560_sensor_isr(13); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_14() { _ech1560_sensor_isr(14); } +void ICACHE_RAM_ATTR _ech1560_sensor_isr_15() { _ech1560_sensor_isr(15); } + +static void (*_ech1560_sensor_isr_list[10])() = { + _ech1560_sensor_isr_0, _ech1560_sensor_isr_1, _ech1560_sensor_isr_2, + _ech1560_sensor_isr_3, _ech1560_sensor_isr_4, _ech1560_sensor_isr_5, + _ech1560_sensor_isr_12, _ech1560_sensor_isr_13, _ech1560_sensor_isr_14, + _ech1560_sensor_isr_15 +}; + +void ECH1560Sensor::_attach(ECH1560Sensor * instance, unsigned char gpio, unsigned char mode) { + if (!_validGPIO(gpio)) return; + _detach(gpio); + unsigned char index = gpio > 5 ? gpio-6 : gpio; + _ech1560_sensor_instance[index] = instance; + attachInterrupt(gpio, _ech1560_sensor_isr_list[index], mode); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, instance->description().c_str()); + #endif +} + +void ECH1560Sensor::_detach(unsigned char gpio) { + if (!_validGPIO(gpio)) return; + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_ech1560_sensor_instance[index]) { + detachInterrupt(gpio); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, _ech1560_sensor_instance[index]->description().c_str()); + #endif + _ech1560_sensor_instance[index] = NULL; + } +} diff --git a/code/espurna/sensors/EventSensor.h b/code/espurna/sensors/EventSensor.h index 9db786ba..c14f92f9 100644 --- a/code/espurna/sensors/EventSensor.h +++ b/code/espurna/sensors/EventSensor.h @@ -22,7 +22,7 @@ class EventSensor : public BaseSensor { } ~EventSensor() { - detach(_gpio); + _enableInterrupts(false); } // --------------------------------------------------------------------- @@ -68,9 +68,8 @@ class EventSensor : public BaseSensor { // Initialization method, must be idempotent // Defined outside the class body void begin() { - if (_interrupt_gpio != GPIO_NONE) detach(_interrupt_gpio); pinMode(_gpio, _mode); - attach(this, _gpio, _interrupt_mode); + _enableInterrupts(true); } // Descriptive name of the sensor @@ -101,7 +100,7 @@ class EventSensor : public BaseSensor { } // Handle interrupt calls - void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) { + void handleInterrupt(unsigned char gpio) { (void) gpio; static unsigned long last = 0; if (millis() - last > _debounce) { @@ -110,19 +109,29 @@ class EventSensor : public BaseSensor { } } - // Interrupt attach callback - void attached(unsigned char gpio) { - BaseSensor::attached(gpio); - _interrupt_gpio = gpio; - } + protected: - // Interrupt detach callback - void detached(unsigned char gpio) { - BaseSensor::detached(gpio); - if (_interrupt_gpio == gpio) _interrupt_gpio = GPIO_NONE; - } + // --------------------------------------------------------------------- + // Interrupt management + // --------------------------------------------------------------------- - protected: + void _attach(EventSensor * instance, unsigned char gpio, unsigned char mode); + void _detach(unsigned char gpio); + + void _enableInterrupts(bool value) { + + static unsigned char _interrupt_gpio = GPIO_NONE; + + if (value) { + if (_interrupt_gpio != GPIO_NONE) _detach(_interrupt_gpio); + _attach(this, _gpio, _interrupt_mode); + _interrupt_gpio = _gpio; + } else if (_interrupt_gpio != GPIO_NONE) { + _detach(_interrupt_gpio); + _interrupt_gpio = GPIO_NONE; + } + + } // --------------------------------------------------------------------- // Protected @@ -133,6 +142,59 @@ class EventSensor : public BaseSensor { unsigned char _gpio; unsigned char _mode; unsigned char _interrupt_mode; - unsigned char _interrupt_gpio = GPIO_NONE; }; + +// ----------------------------------------------------------------------------- +// Interrupt helpers +// ----------------------------------------------------------------------------- + +EventSensor * _event_sensor_instance[10] = {NULL}; + +void ICACHE_RAM_ATTR _event_sensor_isr(unsigned char gpio) { + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_event_sensor_instance[index]) { + _event_sensor_instance[index]->handleInterrupt(gpio); + } +} + +void ICACHE_RAM_ATTR _event_sensor_isr_0() { _event_sensor_isr(0); } +void ICACHE_RAM_ATTR _event_sensor_isr_1() { _event_sensor_isr(1); } +void ICACHE_RAM_ATTR _event_sensor_isr_2() { _event_sensor_isr(2); } +void ICACHE_RAM_ATTR _event_sensor_isr_3() { _event_sensor_isr(3); } +void ICACHE_RAM_ATTR _event_sensor_isr_4() { _event_sensor_isr(4); } +void ICACHE_RAM_ATTR _event_sensor_isr_5() { _event_sensor_isr(5); } +void ICACHE_RAM_ATTR _event_sensor_isr_12() { _event_sensor_isr(12); } +void ICACHE_RAM_ATTR _event_sensor_isr_13() { _event_sensor_isr(13); } +void ICACHE_RAM_ATTR _event_sensor_isr_14() { _event_sensor_isr(14); } +void ICACHE_RAM_ATTR _event_sensor_isr_15() { _event_sensor_isr(15); } + +static void (*_event_sensor_isr_list[10])() = { + _event_sensor_isr_0, _event_sensor_isr_1, _event_sensor_isr_2, + _event_sensor_isr_3, _event_sensor_isr_4, _event_sensor_isr_5, + _event_sensor_isr_12, _event_sensor_isr_13, _event_sensor_isr_14, + _event_sensor_isr_15 +}; + +void EventSensor::_attach(EventSensor * instance, unsigned char gpio, unsigned char mode) { + if (!_validGPIO(gpio)) return; + _detach(gpio); + unsigned char index = gpio > 5 ? gpio-6 : gpio; + _event_sensor_instance[index] = instance; + attachInterrupt(gpio, _event_sensor_isr_list[index], mode); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, instance->description().c_str()); + #endif +} + +void EventSensor::_detach(unsigned char gpio) { + if (!_validGPIO(gpio)) return; + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_event_sensor_instance[index]) { + detachInterrupt(gpio); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, _event_sensor_instance[index]->description().c_str()); + #endif + _event_sensor_instance[index] = NULL; + } +} diff --git a/code/espurna/sensors/HLW8012Sensor.h b/code/espurna/sensors/HLW8012Sensor.h index e39c3792..a5c66efe 100644 --- a/code/espurna/sensors/HLW8012Sensor.h +++ b/code/espurna/sensors/HLW8012Sensor.h @@ -26,8 +26,7 @@ class HLW8012Sensor : public BaseSensor { } ~HLW8012Sensor() { - detach(_interrupt_cf); - detach(_interrupt_cf1); + _enableInterrupts(false); } void expectedCurrent(double expected) { @@ -141,13 +140,13 @@ class HLW8012Sensor : public BaseSensor { // Handle interrupts #if HLW8012_USE_INTERRUPTS - _enable(true); + _enableInterrupts(true); #else _onconnect_handler = WiFi.onStationModeGotIP([this](WiFiEventStationModeGotIP ipInfo) { - _enable(true); + _enableInterrupts(true); }); _ondisconnect_handler = WiFi.onStationModeDisconnected([this](WiFiEventStationModeDisconnected ipInfo) { - _enable(false); + _enableInterrupts(false); }); #endif @@ -188,54 +187,55 @@ class HLW8012Sensor : public BaseSensor { return 0; } + // Toggle between current and voltage monitoring + #if HLW8012_USE_INTERRUPTS == 0 // Post-read hook (usually to reset things) - void post() { - // Toggle between current and voltage monitoring - #if (HLW8012_USE_INTERRUPTS == 0) - _hlw8012->toggleMode(); - #endif // (HLW8012_USE_INTERRUPTS == 0) - } + void post() { _hlw8012->toggleMode(); } + #endif // HLW8012_USE_INTERRUPTS == 0 // Handle interrupt calls void ICACHE_RAM_ATTR handleInterrupt(unsigned char gpio) { - if (gpio == _interrupt_cf) _hlw8012->cf_interrupt(); - if (gpio == _interrupt_cf1) _hlw8012->cf1_interrupt(); - } - - // Interrupt attach callback - void attached(unsigned char gpio) { - BaseSensor::attached(gpio); - if (_cf == gpio) _interrupt_cf = gpio; - if (_cf1 == gpio) _interrupt_cf1 = gpio; - } - - // Interrupt detach callback - void detached(unsigned char gpio) { - BaseSensor::detached(gpio); - if (_interrupt_cf == gpio) _interrupt_cf = GPIO_NONE; - if (_interrupt_cf1 == gpio) _interrupt_cf1 = GPIO_NONE; + if (gpio == _cf) _hlw8012->cf_interrupt(); + if (gpio == _cf1) _hlw8012->cf1_interrupt(); } protected: // --------------------------------------------------------------------- - // Protected + // Interrupt management // --------------------------------------------------------------------- - void _enable(bool value) { + void _attach(HLW8012Sensor * instance, unsigned char gpio, unsigned char mode); + void _detach(unsigned char gpio); + + void _enableInterrupts(bool value) { + + static unsigned char _interrupt_cf = GPIO_NONE; + static unsigned char _interrupt_cf1 = GPIO_NONE; + if (value) { + if (_interrupt_cf != _cf) { - detach(_interrupt_cf); - attach(this, _cf, CHANGE); + if (_interrupt_cf != GPIO_NONE) _detach(_interrupt_cf); + _attach(this, _cf, CHANGE); + _interrupt_cf = _cf; } + if (_interrupt_cf1 != _cf1) { - detach(_interrupt_cf1); - attach(this, _cf1, CHANGE); + if (_interrupt_cf1 != GPIO_NONE) _detach(_interrupt_cf1); + _attach(this, _cf1, CHANGE); + _interrupt_cf1 = _cf1; } + } else { - detach(_interrupt_cf); - detach(_interrupt_cf1); + + _detach(_cf); + _detach(_cf1); + _interrupt_cf = GPIO_NONE; + _interrupt_cf1 = GPIO_NONE; + } + } // --------------------------------------------------------------------- @@ -247,10 +247,63 @@ class HLW8012Sensor : public BaseSensor { HLW8012 * _hlw8012 = NULL; - WiFiEventHandler _onconnect_handler; - WiFiEventHandler _ondisconnect_handler; + #if HLW8012_USE_INTERRUPTS == 0 + WiFiEventHandler _onconnect_handler; + WiFiEventHandler _ondisconnect_handler; + #endif - unsigned char _interrupt_cf = GPIO_NONE; - unsigned char _interrupt_cf1 = GPIO_NONE; +}; +// ----------------------------------------------------------------------------- +// Interrupt helpers +// ----------------------------------------------------------------------------- + +HLW8012Sensor * _hlw8012_sensor_instance[10] = {NULL}; + +void ICACHE_RAM_ATTR _hlw8012_sensor_isr(unsigned char gpio) { + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_hlw8012_sensor_instance[index]) { + _hlw8012_sensor_instance[index]->handleInterrupt(gpio); + } +} + +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_0() { _hlw8012_sensor_isr(0); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_1() { _hlw8012_sensor_isr(1); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_2() { _hlw8012_sensor_isr(2); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_3() { _hlw8012_sensor_isr(3); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_4() { _hlw8012_sensor_isr(4); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_5() { _hlw8012_sensor_isr(5); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_12() { _hlw8012_sensor_isr(12); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_13() { _hlw8012_sensor_isr(13); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_14() { _hlw8012_sensor_isr(14); } +void ICACHE_RAM_ATTR _hlw8012_sensor_isr_15() { _hlw8012_sensor_isr(15); } + +static void (*_hlw8012_sensor_isr_list[10])() = { + _hlw8012_sensor_isr_0, _hlw8012_sensor_isr_1, _hlw8012_sensor_isr_2, + _hlw8012_sensor_isr_3, _hlw8012_sensor_isr_4, _hlw8012_sensor_isr_5, + _hlw8012_sensor_isr_12, _hlw8012_sensor_isr_13, _hlw8012_sensor_isr_14, + _hlw8012_sensor_isr_15 }; + +void HLW8012Sensor::_attach(HLW8012Sensor * instance, unsigned char gpio, unsigned char mode) { + if (!_validGPIO(gpio)) return; + _detach(gpio); + unsigned char index = gpio > 5 ? gpio-6 : gpio; + _hlw8012_sensor_instance[index] = instance; + attachInterrupt(gpio, _hlw8012_sensor_isr_list[index], mode); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, instance->description().c_str()); + #endif +} + +void HLW8012Sensor::_detach(unsigned char gpio) { + if (!_validGPIO(gpio)) return; + unsigned char index = gpio > 5 ? gpio-6 : gpio; + if (_hlw8012_sensor_instance[index]) { + detachInterrupt(gpio); + #if SENSOR_DEBUG + DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, _hlw8012_sensor_instance[index]->description().c_str()); + #endif + _hlw8012_sensor_instance[index] = NULL; + } +}