Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.7 KiB

  1. // -----------------------------------------------------------------------------
  2. // Abstract sensor class (other sensor classes extend this class)
  3. // Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. // -----------------------------------------------------------------------------
  5. #pragma once
  6. #include <Arduino.h>
  7. typedef enum magnitude_t {
  8. MAGNITUDE_NONE = 0,
  9. MAGNITUDE_TEMPERATURE,
  10. MAGNITUDE_HUMIDITY,
  11. MAGNITUDE_PRESSURE,
  12. MAGNITUDE_CURRENT,
  13. MAGNITUDE_VOLTAGE,
  14. MAGNITUDE_POWER_ACTIVE,
  15. MAGNITUDE_POWER_APPARENT,
  16. MAGNITUDE_POWER_REACTIVE,
  17. MAGNITUDE_ENERGY,
  18. MAGNITUDE_ENERGY_DELTA,
  19. MAGNITUDE_POWER_FACTOR,
  20. MAGNITUDE_ANALOG,
  21. MAGNITUDE_DIGITAL,
  22. MAGNITUDE_EVENTS,
  23. MAGNITUDE_PM1dot0,
  24. MAGNITUDE_PM2dot5,
  25. MAGNITUDE_PM10,
  26. MAGNITUDE_CO2,
  27. MAGNITUDE_MAX,
  28. } magnitude_t;
  29. #define GPIO_NONE 0x99
  30. #define SENSOR_ERROR_OK 0 // No error
  31. #define SENSOR_ERROR_OUT_OF_RANGE 1 // Result out of sensor range
  32. #define SENSOR_ERROR_WARM_UP 2 // Sensor is warming-up
  33. #define SENSOR_ERROR_TIMEOUT 3 // Response from sensor timed out
  34. #define SENSOR_ERROR_UNKNOWN_ID 4 // Sensor did not report a known ID
  35. #define SENSOR_ERROR_CRC 5 // Sensor data corrupted
  36. #define SENSOR_ERROR_I2C 6 // Wrong or locked I2C address
  37. class BaseSensor {
  38. public:
  39. // Constructor
  40. BaseSensor() {}
  41. // Destructor
  42. ~BaseSensor() {}
  43. // Initialization method, must be idempotent
  44. virtual void begin() {}
  45. // Loop-like method, call it in your main loop
  46. virtual void tick() {}
  47. // Pre-read hook (usually to populate registers with up-to-date data)
  48. virtual void pre() {}
  49. // Post-read hook (usually to reset things)
  50. virtual void post() {}
  51. // Descriptive name of the sensor
  52. virtual String name() {}
  53. // Descriptive name of the slot # index
  54. virtual String slot(unsigned char index) {}
  55. // Type for slot # index
  56. virtual magnitude_t type(unsigned char index) {}
  57. // Current value for slot # index
  58. virtual double value(unsigned char index) {}
  59. // Specific for I2C sensors
  60. unsigned char lock_i2c(unsigned char address, size_t size, unsigned char * addresses) {
  61. // Check if we should release a previously locked address
  62. if (_previous_address != address) {
  63. i2cReleaseLock(_previous_address);
  64. }
  65. // If we have already an address, check it is not locked
  66. if (address && !i2cGetLock(address)) {
  67. _error = SENSOR_ERROR_I2C;
  68. // If we don't have an address...
  69. } else {
  70. // Trigger auto-discover
  71. address = i2cFindAndLock(size, addresses);
  72. // If still nothing exit with error
  73. if (address == 0) _error = SENSOR_ERROR_I2C;
  74. }
  75. _previous_address = address;
  76. return address;
  77. }
  78. // Return sensor status (true for ready)
  79. bool status() { return _error == 0; }
  80. // Return sensor last internal error
  81. int error() { return _error; }
  82. // Number of available slots
  83. unsigned char count() { return _count; }
  84. // Handle interrupt calls
  85. virtual void handleInterrupt(unsigned char gpio) {}
  86. // Interrupt attach callback
  87. void attached(unsigned char gpio) {
  88. #if SENSOR_DEBUG
  89. DEBUG_MSG("[SENSOR] GPIO%d interrupt attached to %s\n", gpio, name().c_str());
  90. #endif
  91. }
  92. // Interrupt detach callback
  93. void detached(unsigned char gpio) {
  94. #if SENSOR_DEBUG
  95. DEBUG_MSG("[SENSOR] GPIO%d interrupt detached from %s\n", gpio, name().c_str());
  96. #endif
  97. }
  98. protected:
  99. // Attach interrupt
  100. void attach(BaseSensor * instance, unsigned char gpio, unsigned char mode);
  101. // Detach interrupt
  102. void detach(unsigned char gpio);
  103. int _error = 0;
  104. bool _dirty = true;
  105. unsigned char _count = 0;
  106. // I2C
  107. unsigned char _previous_address = 0;
  108. unsigned char _address = 0;
  109. };
  110. // -----------------------------------------------------------------------------
  111. // Interrupt helpers
  112. // -----------------------------------------------------------------------------
  113. BaseSensor * _isr_sensor_instance[16] = {NULL};
  114. void _sensor_isr(unsigned char gpio) {
  115. if (_isr_sensor_instance[gpio]) {
  116. _isr_sensor_instance[gpio]->handleInterrupt(gpio);
  117. }
  118. }
  119. void _sensor_isr_0() { _sensor_isr(0); }
  120. void _sensor_isr_2() { _sensor_isr(2); }
  121. void _sensor_isr_4() { _sensor_isr(4); }
  122. void _sensor_isr_5() { _sensor_isr(5); }
  123. void _sensor_isr_12() { _sensor_isr(12); }
  124. void _sensor_isr_13() { _sensor_isr(13); }
  125. void _sensor_isr_14() { _sensor_isr(14); }
  126. void _sensor_isr_15() { _sensor_isr(15); }
  127. void (*_sensor_isrs[16])() = {
  128. _sensor_isr_0, NULL, _sensor_isr_2, NULL, _sensor_isr_4, _sensor_isr_5,
  129. NULL, NULL, NULL, NULL, NULL, NULL,
  130. _sensor_isr_12, _sensor_isr_13, _sensor_isr_14, _sensor_isr_15
  131. };
  132. void BaseSensor::attach(BaseSensor * instance, unsigned char gpio, unsigned char mode) {
  133. detach(gpio);
  134. if (_sensor_isrs[gpio]) {
  135. _isr_sensor_instance[gpio] = instance;
  136. attachInterrupt(gpio, _sensor_isrs[gpio], mode);
  137. instance->attached(gpio);
  138. }
  139. }
  140. void BaseSensor::detach(unsigned char gpio) {
  141. if (_isr_sensor_instance[gpio]) {
  142. detachInterrupt(gpio);
  143. _isr_sensor_instance[gpio]->detached(gpio);
  144. _isr_sensor_instance[gpio] = NULL;
  145. }
  146. }