From 90a7f7f6d2e6d18cd7f86d52ca661f224d76d44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xose=20P=C3=A9rez?= Date: Wed, 20 Dec 2017 13:20:56 +0100 Subject: [PATCH] Interrupt handling routines for sensors --- code/espurna/config/sensors.h | 2 + code/espurna/sensor.ino | 14 +---- code/espurna/sensors/BaseSensor.h | 71 +++++++++++++++++++++++- code/espurna/sensors/EmonADS1X15Sensor.h | 2 +- code/espurna/sensors/EmonSensor.h | 6 +- code/espurna/sensors/EventSensor.h | 45 ++++++++++++--- 6 files changed, 112 insertions(+), 28 deletions(-) diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index 4e6bf60c..6de54b25 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -2,6 +2,8 @@ // SENSORS // ----------------------------------------------------------------------------- +#define SENSOR_DEBUG 0 // Debug sensors (always to 0 in prod) + #define SENSOR_READ_INTERVAL 6000 // Read data from sensors every 6 seconds #define SENSOR_REPORT_EVERY 10 // Report every this many readings #define SENSOR_USE_INDEX 0 // Use the index in topic (i.e. temperature/0) diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index 6b12bd6c..52ef5ade 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -190,17 +190,6 @@ void _sensorPost() { } } -// ----------------------------------------------------------------------------- -// Interrupts -// ----------------------------------------------------------------------------- - -#if EVENTS_SUPPORT -unsigned char _event_sensor_id = 0; -void _isrEventSensor() { - _sensors[_event_sensor_id]->InterruptHandler(); -} -#endif // EVENTS_SUPPORT - // ----------------------------------------------------------------------------- // Sensor initialization // ----------------------------------------------------------------------------- @@ -293,9 +282,8 @@ void _sensorInit() { EventSensor * sensor = new EventSensor(); sensor->setGPIO(EVENTS_PIN, EVENTS_PIN_MODE); sensor->setDebounceTime(EVENTS_DEBOUNCE); + sensor->setinterruptMode(EVENTS_INTERRUPT_MODE); _sensorRegister(sensor); - _event_sensor_id = sensorCount() - 1; - attachInterrupt(EVENTS_PIN, _isrEventSensor, EVENTS_INTERRUPT_MODE); } #endif diff --git a/code/espurna/sensors/BaseSensor.h b/code/espurna/sensors/BaseSensor.h index a1ce002a..2dbae59d 100644 --- a/code/espurna/sensors/BaseSensor.h +++ b/code/espurna/sensors/BaseSensor.h @@ -38,6 +38,8 @@ typedef enum magnitude_t { } magnitude_t; +#define GPIO_NONE 0x99 + #define SENSOR_ERROR_OK 0 // No error #define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range #define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up @@ -55,9 +57,6 @@ class BaseSensor { // Destructor ~BaseSensor() {} - // General interrupt handler - virtual void InterruptHandler() {} - // Initialization method, must be idempotent virtual void begin() {} @@ -91,11 +90,77 @@ class BaseSensor { // Number of available slots unsigned char count() { return _count; } + // Handle interrupt calls + virtual void handleInterrupt(unsigned char gpio) {} + + // Interrupt attach callback + void attached(unsigned char gpio) { + #if SENSOR_DEBUG + Serial.printf("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, name().c_str()); + #endif + } + + // Interrupt detach callback + void detached(unsigned char gpio) { + #if SENSOR_DEBUG + Serial.printf("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, name().c_str()); + #endif + } protected: + // Attach interrupt + void attach(BaseSensor * instance, unsigned char gpio, unsigned char mode); + + // Detach interrupt + void detach(unsigned char gpio); + int _error = 0; unsigned char _count = 0; }; + +// ----------------------------------------------------------------------------- +// Interrupt helpers +// ----------------------------------------------------------------------------- + +BaseSensor * _isr_sensor_instance[16] = {NULL}; + +void _sensor_isr(unsigned char gpio) { + if (_isr_sensor_instance[gpio]) { + _isr_sensor_instance[gpio]->handleInterrupt(gpio); + } +} + +void _sensor_isr_0() { _sensor_isr(0); } +void _sensor_isr_2() { _sensor_isr(2); } +void _sensor_isr_4() { _sensor_isr(4); } +void _sensor_isr_5() { _sensor_isr(5); } +void _sensor_isr_12() { _sensor_isr(12); } +void _sensor_isr_13() { _sensor_isr(13); } +void _sensor_isr_14() { _sensor_isr(14); } +void _sensor_isr_15() { _sensor_isr(15); } + +void (*_sensor_isrs[16])() = { + _sensor_isr_0, NULL, _sensor_isr_2, NULL, _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) { + 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 (_isr_sensor_instance[gpio]) { + detachInterrupt(gpio); + _isr_sensor_instance[gpio]->detached(gpio); + _isr_sensor_instance[gpio] = NULL; + } +} diff --git a/code/espurna/sensors/EmonADS1X15Sensor.h b/code/espurna/sensors/EmonADS1X15Sensor.h index 8b3baa39..06f0157c 100644 --- a/code/espurna/sensors/EmonADS1X15Sensor.h +++ b/code/espurna/sensors/EmonADS1X15Sensor.h @@ -291,7 +291,7 @@ class EmonADS1X15Sensor : public EmonSensor { } config |= ((channel + 4) << 12); // Set single-ended input channel (0x4000 - 0x7000) - #if EMON_DEBUG + #if SENSOR_DEBUG Serial.printf("[EMON] ADS1X115 Config Registry: %04X\n", config); #endif diff --git a/code/espurna/sensors/EmonSensor.h b/code/espurna/sensors/EmonSensor.h index 3a7caf25..09774f9b 100644 --- a/code/espurna/sensors/EmonSensor.h +++ b/code/espurna/sensors/EmonSensor.h @@ -8,8 +8,6 @@ #include "Arduino.h" #include "BaseSensor.h" -#define EMON_DEBUG 0 - class EmonSensor : public BaseSensor { public: @@ -65,7 +63,7 @@ class EmonSensor : public BaseSensor { m = s * i; } - #if EMON_DEBUG + #if SENSOR_DEBUG Serial.print("[EMON] Current ratio: "); Serial.println(ratio); Serial.print("[EMON] Ref. Voltage: "); Serial.println(ref); Serial.print("[EMON] ADC Counts: "); Serial.println(_adc_counts); @@ -120,7 +118,7 @@ class EmonSensor : public BaseSensor { current = (double) (int(current * _multiplier) - 1) / _multiplier; if (current < 0) current = 0; - #if EMON_DEBUG + #if SENSOR_DEBUG Serial.print("[EMON] Total samples: "); Serial.println(_samples); Serial.print("[EMON] Total time (ms): "); Serial.println(time_span); Serial.print("[EMON] Sample frequency (Hz): "); Serial.println(1000 * _samples / time_span); diff --git a/code/espurna/sensors/EventSensor.h b/code/espurna/sensors/EventSensor.h index 61aef1e9..b4d588d2 100644 --- a/code/espurna/sensors/EventSensor.h +++ b/code/espurna/sensors/EventSensor.h @@ -20,11 +20,19 @@ class EventSensor : public BaseSensor { _count = 1; } + ~EventSensor() { + detachInterrupt(_gpio); + } + void setGPIO(unsigned char gpio, int mode = INPUT) { _gpio = gpio; pinMode(_gpio, mode); } + void setinterruptMode(unsigned long mode) { + _mode = mode; + } + void setDebounceTime(unsigned long debounce) { _debounce = debounce; } @@ -33,12 +41,11 @@ class EventSensor : public BaseSensor { // Sensors API // --------------------------------------------------------------------- - void InterruptHandler() { - static unsigned long last = 0; - if (millis() - last > _debounce) { - _events = _events + 1; - last = millis(); - } + // Initialization method, must be idempotent + // Defined outside the class body + void begin() { + if (_interrupt_gpio != GPIO_NONE) detach(_interrupt_gpio); + attach(this, _gpio, _mode); } // Descriptive name of the sensor @@ -50,6 +57,7 @@ class EventSensor : public BaseSensor { // Descriptive name of the slot # index String slot(unsigned char index) { + (void) index; return name(); } @@ -73,6 +81,27 @@ class EventSensor : public BaseSensor { return 0; } + // Handle interrupt calls + void handleInterrupt(unsigned char gpio) { + (void) gpio; + static unsigned long last = 0; + if (millis() - last > _debounce) { + _events = _events + 1; + last = millis(); + } + } + + // 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; + } protected: @@ -81,7 +110,9 @@ class EventSensor : public BaseSensor { // --------------------------------------------------------------------- volatile unsigned long _events = 0; - unsigned long _debounce = 0; + unsigned long _debounce = EVENTS_DEBOUNCE; unsigned char _gpio; + unsigned char _interrupt_gpio = GPIO_NONE; + unsigned char _mode; };