|
|
- // -----------------------------------------------------------------------------
- // Abstract sensor class (other sensor classes extend this class)
- // Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
- // -----------------------------------------------------------------------------
-
- #pragma once
-
- #include <Arduino.h>
- #include <ArduinoJson.h>
-
- typedef enum magnitude_t {
-
- MAGNITUDE_NONE = 0,
-
- MAGNITUDE_TEMPERATURE,
- MAGNITUDE_HUMIDITY,
- MAGNITUDE_PRESSURE,
-
- MAGNITUDE_CURRENT,
- MAGNITUDE_VOLTAGE,
- MAGNITUDE_POWER_ACTIVE,
- MAGNITUDE_POWER_APPARENT,
- MAGNITUDE_POWER_REACTIVE,
- MAGNITUDE_ENERGY,
- MAGNITUDE_ENERGY_DELTA,
- MAGNITUDE_POWER_FACTOR,
-
- MAGNITUDE_ANALOG,
- MAGNITUDE_DIGITAL,
- MAGNITUDE_EVENTS,
-
- MAGNITUDE_PM1dot0,
- MAGNITUDE_PM2dot5,
- MAGNITUDE_PM10,
-
- MAGNITUDE_CO2,
-
- MAGNITUDE_MAX,
-
- } 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
- #define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
- #define SENSOR_ERROR_UNKNOWN_ID 4 // Sensor did not report a known ID
- #define SENSOR_ERROR_CRC 5 // Sensor data corrupted
- #define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
-
- class BaseSensor {
-
- public:
-
- // Constructor
- BaseSensor() {}
-
- // Destructor
- ~BaseSensor() {}
-
- // Initialization method, must be idempotent
- virtual void begin() {}
-
- // Loop-like method, call it in your main loop
- virtual void tick() {}
-
- // Pre-read hook (usually to populate registers with up-to-date data)
- virtual void pre() {}
-
- // Post-read hook (usually to reset things)
- virtual void post() {}
-
- // Descriptive name of the sensor
- virtual String description() {}
-
- // Type for slot # index
- virtual magnitude_t type(unsigned char index) {}
-
- // Current value for slot # index
- virtual double value(unsigned char index) {}
-
- // Retrieve current instance configuration
- virtual void getConfig(JsonObject& root) {};
-
- // Save current instance configuration
- virtual void setConfig(JsonObject& root) {};
-
- // Load the configuration manifest
- static void manifest(JsonArray& root) {};
-
- // Descriptive name of the slot # index
- String slot(unsigned char index) { return description(); }
-
- // Sensor ID
- unsigned char getID() { return _sensor_id; };
-
- // Specific for I2C sensors
- unsigned char lock_i2c(unsigned char address, size_t size, unsigned char * addresses) {
-
- // Check if we should release a previously locked address
- if (_previous_address != address) {
- i2cReleaseLock(_previous_address);
- }
-
- // If we have already an address, check it is not locked
- if (address && !i2cGetLock(address)) {
- _error = SENSOR_ERROR_I2C;
-
- // If we don't have an address...
- } else {
-
- // Trigger auto-discover
- address = i2cFindAndLock(size, addresses);
-
- // If still nothing exit with error
- if (address == 0) _error = SENSOR_ERROR_I2C;
-
- }
-
- _previous_address = address;
- return address;
-
- }
-
- // 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; }
-
- // Return sensor last internal error
- int error() { return _error; }
-
- // Number of available slots
- unsigned char count() { return _count; }
-
- // Handle interrupt calls
- virtual void handleInterrupt(unsigned char gpio) {}
-
- protected:
-
- // Attach interrupt
- void attach(BaseSensor * instance, unsigned char gpio, unsigned char mode);
-
- // Detach interrupt
- void detach(unsigned char gpio);
-
- unsigned char _sensor_id = 0x00;
- int _error = 0;
- bool _dirty = true;
- unsigned char _count = 0;
-
- // I2C
- unsigned char _previous_address = 0;
- unsigned char _address = 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;
- }
- }
|