From 0180a0342ff3c68048357e8971d18ec4d7a11eea Mon Sep 17 00:00:00 2001 From: Stefan Brand Date: Tue, 2 Feb 2021 21:12:31 +0100 Subject: [PATCH] Add Some Prototype Code for the SG112A/B CO2 Sensor --- lib/SG112A/SG112A.cpp | 69 ++++++++++++++++++++++++++++++++++++++----- lib/SG112A/SG112A.h | 16 ++++++++-- src/config.h.example | 3 ++ src/main.cpp | 5 +++- 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/lib/SG112A/SG112A.cpp b/lib/SG112A/SG112A.cpp index ccf3add..daf8802 100644 --- a/lib/SG112A/SG112A.cpp +++ b/lib/SG112A/SG112A.cpp @@ -1,22 +1,77 @@ #include #include "SG112A.h" -void GA112A(void) { - +SG112A::SG112A(void) { + Serial.begin(9600); + Serial.setTimeout(READ_TIMEOUT); + delay(5000); + write(CMD_GET_PPM); + read(); } void SG112A::getSensorData(lora_data &loradata) { + write(CMD_GET_PPM); + delay(50); + uint8_t byteLen = read(); + if (byteLen > 0) { + switch(buffer[3]) { + case 0x15: + loradata.ppm = (buffer[5]*256) + buffer[4]; + break; + } + } } -uint16_t SG112A::getPPM(void) { - +void SG112A::write(byte cmd) { + uint8_t _cmd[6] = {0xAA, 0x55, cmd, 0x00, 0x00, 0x00}; + uint16_t crc = crc16(_cmd, 4); + _cmd[4] = (uint8_t)(crc & 0xFF); + _cmd[5] = (uint8_t)(crc >> 8); + while (Serial.available() > 0) Serial.read(); + Serial.write(_cmd, 6); + Serial.flush(); } -void SG112A::sendCmd(uint8_t *cmd, uint8_t len) { +uint8_t SG112A::read() { + uint8_t ret = 0; + zeroBuffer(); + if (Serial.available() > 0) { + ret = Serial.readBytes(buffer, SER_BUF_LEN); + } + if (buffer[0] != 0xBB && buffer[1] != 0x66) + ret = 0; + + // TODO: Do CRC Check Here + + return ret; } -uint16_t SG112A::crc16(uint8_t *cmd, uint8_t len){ - +void SG112A::zeroBuffer() { + for (int i=0; i < SER_BUF_LEN; i++) + buffer[i] = 0x00; +} + +uint16_t SG112A::crc16(uint8_t *cmd, int len){ + uint16_t ret = 0xffff; + uint16_t polynomial = 0xa001; + int shift = 0x0; + int i = 0; + for (i = len - 1; i >= 0 ; i-- ){ + + uint16_t code = ( uint16_t )( cmd [ len -1 - i ] & 0xff ); + ret = ret^code; + shift = 0x0; + while ( shift <= 7 ){ + if ( ret & 0x1 ) { + ret = ret >> 1; + ret = ret^polynomial ; + } else { + ret = ret >> 1; + } + shift++; + } + } + return ret; } diff --git a/lib/SG112A/SG112A.h b/lib/SG112A/SG112A.h index bd7c617..df42d90 100644 --- a/lib/SG112A/SG112A.h +++ b/lib/SG112A/SG112A.h @@ -6,11 +6,23 @@ struct lora_data { int16_t ppm; } __attribute__ ((packed)); +#define READ_TIMEOUT 500 +#define SER_BUF_LEN 16 + +#define CMD_GET_VER 0x10 +#define CMD_GET_SER 0x12 +#define CMD_GET_PPM 0x14 + class SG112A { private: - void sendCmd(uint8_t *cmd, uint8_t len); - uint16_t crc16(uint8_t *cmd, uint8_t len); + uint8_t buffer[SER_BUF_LEN]; + + void write(byte cmd); + uint8_t read(); + void zeroBuffer(void); + uint16_t crc16(uint8_t *cmd, int len); uint16_t getPPM(void); + public: SG112A(void); void getSensorData(lora_data &loradata); diff --git a/src/config.h.example b/src/config.h.example index 9fc253f..3bc075a 100644 --- a/src/config.h.example +++ b/src/config.h.example @@ -3,11 +3,14 @@ #define LED_PIN PIN_PA7 // Enable Serial Debugging. Parameters for the Serial Port are 115200 +// Please be aware that the SG112A/B CO2 Sensor uses the HW-UART, so +// Serial Debug Output is not available with this Sensor. // #define DEBUG // Define which Sensor is installed #define HAS_BME280 // #define HAS_SHT21 +// #define HAS_SG112A // #define HAS_NO_SENSOR // How many minutes to sleep between Measuring/Sending diff --git a/src/main.cpp b/src/main.cpp index b948b21..5950170 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,9 @@ void blink(uint8_t num) { struct lora_data { uint8_t bat; } __attribute ((packed)); +#elif defined HAS_SG112A + #include + SG112A sensor; #elif defined HAS_BME280 #include BME280 sensor; @@ -68,7 +71,7 @@ const lmic_pinmap lmic_pins = { }; // List of unused Pins - will be disabled for Power Saving -#ifdef DEBUG +#if defined DEBUG || defined HAS_SG112A const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0}; #else const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB3, PIN_PB2, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0};