Skip to content

Commit

Permalink
sns: attachInterruptArg() instead of storing pin info in iram
Browse files Browse the repository at this point in the history
simplify isr code, since esp{8266,32} Cores allow to pass void* argument to the isr
also allows to seamlessly lock the gpio (but, outside does not yet check it's result)
  • Loading branch information
mcspr committed Nov 22, 2021
1 parent b725944 commit 9db679f
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 503 deletions.
60 changes: 60 additions & 0 deletions code/espurna/sensors/BaseSensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,66 @@

class BaseSensor {
public:
// Generic way to pass the sensor instance to the isr
struct InterruptablePin {
InterruptablePin() = default;
~InterruptablePin() {
detach();
}

template <typename T, typename TypedCallback = void(*)(T*)>
void attach(T* instance, TypedCallback callback, int mode) {
_attach(static_cast<void*>(instance), reinterpret_cast<VoidCallback>(callback), mode);
}

InterruptablePin& operator=(unsigned char pin) {
_pin = pin;
return *this;
}

bool operator==(unsigned char other) const {
return _pin == other;
}

explicit operator String() const {
return String(_pin);
}

void detach() {
gpioUnlock(_current);
::detachInterrupt(_current);
_current = GPIO_NONE;
}

void pin(unsigned char value) {
_pin = value;
}

unsigned char pin() const {
return _pin;
}

private:
using VoidCallback = void(*)(void*);

void _attach(void* instance, VoidCallback callback, int mode) {
if (_current != _pin) {
if (!gpioLock(_pin)) {
return;
}

detach();
::attachInterruptArg(_pin, callback, instance, mode);

_current = _pin;
}
}

unsigned char _current { GPIO_NONE };
unsigned char _pin { GPIO_NONE };
};

// Generic container for magnitude types used in the sensor
struct Magnitude {
unsigned char type;
#if __cplusplus <= 201103L
Expand Down
113 changes: 15 additions & 98 deletions code/espurna/sensors/ECH1560Sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ class ECH1560Sensor : public BaseEmonSensor {
findAndAddEnergy(Magnitudes);
}

~ECH1560Sensor() {
_enableInterrupts(false);
}

// ---------------------------------------------------------------------

void setCLK(unsigned char clk) {
Expand All @@ -56,7 +52,7 @@ class ECH1560Sensor : public BaseEmonSensor {
// ---------------------------------------------------------------------

unsigned char getCLK() {
return _clk;
return _clk.pin();
}

unsigned char getMISO() {
Expand All @@ -76,9 +72,9 @@ class ECH1560Sensor : public BaseEmonSensor {

if (!_dirty) return;

pinMode(_clk, INPUT);
pinMode(_clk.pin(), INPUT);
pinMode(_miso, INPUT);
_enableInterrupts(true);
_clk.attach(this, handleInterrupt, RISING);

_dirty = false;
_ready = true;
Expand All @@ -93,7 +89,7 @@ class ECH1560Sensor : public BaseEmonSensor {
// Descriptive name of the sensor
String description() {
char buffer[35];
snprintf(buffer, sizeof(buffer), "ECH1560 (CLK,SDO) @ GPIO(%hhu,%hhu)", _clk, _miso);
snprintf(buffer, sizeof(buffer), "ECH1560 (CLK,SDO) @ GPIO(%hhu,%hhu)", _clk.pin(), _miso);
return String(buffer);
}

Expand All @@ -105,7 +101,7 @@ class ECH1560Sensor : public BaseEmonSensor {
// Address of the sensor (it could be the GPIO or I2C address)
String address(unsigned char index) {
char buffer[6];
snprintf(buffer, sizeof(buffer), "%hhu:%hhu", _clk, _miso);
snprintf(buffer, sizeof(buffer), "%hhu:%hhu", _clk.pin(), _miso);
return String(buffer);
}

Expand All @@ -127,14 +123,19 @@ class ECH1560Sensor : public BaseEmonSensor {
return 0;
}

void IRAM_ATTR handleInterrupt(unsigned char) {
static void IRAM_ATTR handleInterrupt(ECH1560Sensor* instance) {
instance->interrupt();
}

private:
void IRAM_ATTR interrupt() {
// if we are trying to find the sync-time (CLK goes high for 1-2ms)
if (_dosync == false) {
if (!_dosync) {

_clk_count = 0;

// register how long the ClkHigh is high to evaluate if we are at the part where clk goes high for 1-2 ms
while (digitalRead(_clk) == HIGH) {
while (digitalRead(_clk.pin()) == HIGH) {
_clk_count += 1;
delayMicroseconds(30); //can only use delayMicroseconds in an interrupt.
}
Expand All @@ -152,39 +153,9 @@ class ECH1560Sensor : public BaseEmonSensor {
_nextbit = true;

}

}

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;
Expand Down Expand Up @@ -290,8 +261,8 @@ class ECH1560Sensor : public BaseEmonSensor {

// ---------------------------------------------------------------------

unsigned char _clk = 0;
unsigned char _miso = 0;
InterruptablePin _clk{};
unsigned char _miso = GPIO_NONE;
bool _inverted = false;

volatile long _bits_count = 0;
Expand All @@ -311,58 +282,4 @@ class ECH1560Sensor : public BaseEmonSensor {
constexpr BaseEmonSensor::Magnitude ECH1560Sensor::Magnitudes[];
#endif

// -----------------------------------------------------------------------------
// Interrupt helpers
// -----------------------------------------------------------------------------

ECH1560Sensor * _ech1560_sensor_instance[10] = {NULL};

void IRAM_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 IRAM_ATTR _ech1560_sensor_isr_0() { _ech1560_sensor_isr(0); }
void IRAM_ATTR _ech1560_sensor_isr_1() { _ech1560_sensor_isr(1); }
void IRAM_ATTR _ech1560_sensor_isr_2() { _ech1560_sensor_isr(2); }
void IRAM_ATTR _ech1560_sensor_isr_3() { _ech1560_sensor_isr(3); }
void IRAM_ATTR _ech1560_sensor_isr_4() { _ech1560_sensor_isr(4); }
void IRAM_ATTR _ech1560_sensor_isr_5() { _ech1560_sensor_isr(5); }
void IRAM_ATTR _ech1560_sensor_isr_12() { _ech1560_sensor_isr(12); }
void IRAM_ATTR _ech1560_sensor_isr_13() { _ech1560_sensor_isr(13); }
void IRAM_ATTR _ech1560_sensor_isr_14() { _ech1560_sensor_isr(14); }
void IRAM_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 (!gpioValid(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_P(PSTR("[SENSOR] GPIO%d interrupt attached to %s\n"), gpio, instance->description().c_str());
#endif
}

void ECH1560Sensor::_detach(unsigned char gpio) {
if (!gpioValid(gpio)) return;
unsigned char index = gpio > 5 ? gpio-6 : gpio;
if (_ech1560_sensor_instance[index]) {
detachInterrupt(gpio);
#if SENSOR_DEBUG
DEBUG_MSG_P(PSTR("[SENSOR] GPIO%d interrupt detached from %s\n"), gpio, _ech1560_sensor_instance[index]->description().c_str());
#endif
_ech1560_sensor_instance[index] = NULL;
}
}

#endif // SENSOR_SUPPORT && ECH1560_SUPPORT
Loading

0 comments on commit 9db679f

Please sign in to comment.