447 lines
14 KiB
C++
447 lines
14 KiB
C++
#include"bc_co2_module_arduino.h"
|
|
|
|
#define TCA_ADDR 0x38
|
|
#define TCA_REG_INPUT_PORT 0x00
|
|
#define TCA_REG_OUTPUT_PORT 0x01
|
|
#define TCA_POLARITY_INVERSION 0x02
|
|
#define TCA_REG_CONFIG 0x03
|
|
#define TCA_RDY_PIN 7
|
|
#define MODBUS_ADDR 0xfe
|
|
#define MODBUS_WRITE 0x41
|
|
#define MODBUS_READ 0x44
|
|
#define INITIAL_MEASUREMENT 0x10
|
|
#define SEQUENTIAL_MEASUREMENT 0x20
|
|
#define _BC_LP8_RX_ERROR_STATUS0 (3 + 0xa7 - 0x80)
|
|
#define _BC_LP8_RX_ERROR_STATUS1 (3 + 0xa6 - 0x80)
|
|
// #define RX_CONC (3 + 0x9a - 0x80) //no pressure correction or noise filtering
|
|
// #define RX_CONC (3 + 0x9c - 0x80) //pressure correction no noise filtering
|
|
// #define RX_CONC (3 + 0xa8 - 0x80) //no pressure correction, noise filtered
|
|
#define RX_CONC (3 + 0xaa - 0x80) //pressure correction and noise filtering
|
|
|
|
static struct lp8_t sensor;
|
|
unsigned long delay_started = 0;
|
|
bool delay_running = false;
|
|
static bool diag;
|
|
|
|
bool init_co2_module(long baudrate) {
|
|
if(baudrate > 0) {
|
|
diag = true;
|
|
}
|
|
//init comms
|
|
Serial1.begin(9600, SERIAL_8N2); //init Serial comm to lp8 sensor, 8data bits 2 stop bits, no parity
|
|
Wire.begin(); //init arduino i2c
|
|
|
|
reset_module();
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool reset_module() {
|
|
sensor.first_measurement_done = false; //no state writeback
|
|
sensor.calibration_run = false;
|
|
sensor.pressure = 10124;
|
|
sensor.valid = false;
|
|
|
|
//set appropriate port directions
|
|
tca_set_direction(0x00);
|
|
// tca_set_direction(0x08);
|
|
|
|
//set proper pins as outputs
|
|
tca_set_port(0xee);
|
|
//charge the cap
|
|
tca_set_port(0xe8);
|
|
//start non blocking delay to charge the cap
|
|
delay_started = millis();
|
|
delay_running = true;
|
|
|
|
sensor.state = LP8_STATE_INITIALIZE;
|
|
return(true);
|
|
}
|
|
|
|
static void measure(){
|
|
static char i = 0;
|
|
size_t length;
|
|
uint8_t rxbuf;
|
|
|
|
start:
|
|
switch (sensor.state) {
|
|
case LP8_STATE_ERROR:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
Serial.print("error_state: ");
|
|
Serial.println(sensor.error);
|
|
}
|
|
reset_module();
|
|
goto start;
|
|
}
|
|
case LP8_STATE_READY:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
|
|
i = 0;
|
|
tca_set_direction(0x00);
|
|
tca_set_port(0xee);
|
|
|
|
sensor.state = LP8_STATE_INITIALIZE;
|
|
goto start;
|
|
}
|
|
case LP8_STATE_INITIALIZE:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
//wait 15s to ensure cap is sufficiently charged
|
|
if(delay_running && ((millis() - delay_started) >= 15000)) {
|
|
delay_running = false;
|
|
sensor.state = LP8_STATE_PRECHARGE;
|
|
}
|
|
else if(!delay_running) {
|
|
sensor.state = LP8_STATE_PRECHARGE;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
goto start;
|
|
}
|
|
case LP8_STATE_PRECHARGE:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
tca_set_port(0xe8);
|
|
sensor.state = LP8_STATE_CHARGE;
|
|
|
|
goto start;
|
|
}
|
|
case LP8_STATE_CHARGE:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
tca_set_port(0xe0);
|
|
sensor.state = LP8_STATE_BOOT;
|
|
|
|
goto start;
|
|
}
|
|
case LP8_STATE_BOOT:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
while(get_ready_state() != 0) {
|
|
delay(10);
|
|
i++;
|
|
if(i >= 21) { //210ms wait for ready pin
|
|
if(diag) {
|
|
Serial.println("boot_tout!");
|
|
}
|
|
sensor.error = LP8_ERROR_BOOT_TIMEOUT;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
}
|
|
i = 0;
|
|
|
|
if(sensor.first_measurement_done == false){
|
|
sensor.tx_buffer[0] = MODBUS_ADDR;
|
|
sensor.tx_buffer[1] = MODBUS_WRITE;
|
|
sensor.tx_buffer[2] = 0x00;
|
|
sensor.tx_buffer[3] = 0x80;
|
|
sensor.tx_buffer[4] = 0x01;
|
|
sensor.tx_buffer[5] = INITIAL_MEASUREMENT;
|
|
sensor.tx_buffer[6] = 0x28;
|
|
sensor.tx_buffer[7] = 0x7e;
|
|
if(diag) {
|
|
Serial.println("initial_measure");
|
|
}
|
|
length = 8;
|
|
}
|
|
else {
|
|
uint16_t crc16;
|
|
|
|
sensor.tx_buffer[0] = MODBUS_ADDR;
|
|
sensor.tx_buffer[1] = MODBUS_WRITE;
|
|
sensor.tx_buffer[2] = 0x00;
|
|
sensor.tx_buffer[3] = 0x80;
|
|
sensor.tx_buffer[4] = 0x1a;
|
|
|
|
if(sensor.calibration_run == true){
|
|
sensor.tx_buffer[5] = sensor.calibration;
|
|
if(diag) {
|
|
Serial.println("calibration_data");
|
|
}
|
|
}
|
|
else {
|
|
sensor.tx_buffer[5] = SEQUENTIAL_MEASUREMENT;
|
|
if(diag) {
|
|
Serial.println("seq_measure");
|
|
}
|
|
}
|
|
|
|
// memcpy(sensor.tx_buffer[6], sensor.sensor_state, 23);
|
|
while(i < 24){
|
|
sensor.tx_buffer[6 + i] = sensor.sensor_state[i];
|
|
i++;
|
|
}
|
|
if(diag) {
|
|
Serial.println("memcpyied");
|
|
}
|
|
|
|
sensor.tx_buffer[29] = sensor.pressure >> 8;
|
|
sensor.tx_buffer[30] = sensor.pressure;
|
|
|
|
crc16 = calculate_crc16(sensor.tx_buffer, 31);
|
|
|
|
if(diag) {
|
|
Serial.println("calc_crc");
|
|
}
|
|
|
|
sensor.tx_buffer[31] = crc16;
|
|
sensor.tx_buffer[32] = crc16 >> 8;
|
|
|
|
if(diag) {
|
|
Serial.println("buffer_made");
|
|
}
|
|
|
|
i = 0;
|
|
length = 33;
|
|
}
|
|
|
|
Serial1.write(sensor.tx_buffer, length);
|
|
delay(75); //need time to process transmission
|
|
|
|
sensor.state = LP8_STATE_BOOT_READ;
|
|
goto start;
|
|
}
|
|
case LP8_STATE_BOOT_READ:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
|
|
while(1) {
|
|
rxbuf = Serial1.read();
|
|
sensor.rx_buffer[i] = rxbuf;
|
|
i++;
|
|
if(rxbuf == 0xff){
|
|
break;
|
|
}
|
|
}
|
|
if(sensor.rx_buffer[0] != MODBUS_ADDR) {
|
|
sensor.error = LP8_ERROR_BOOT_READ_DEVICE_ADDRESS;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if(sensor.rx_buffer[1] != sensor.tx_buffer[1]) {
|
|
sensor.error = LP8_ERROR_BOOT_READ_COMMAND;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if(calculate_crc16(sensor.rx_buffer, 4) != 0){
|
|
sensor.error = LP8_ERROR_BOOT_READ_CRC;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
i = 0;
|
|
|
|
sensor.state = LP8_STATE_MEASURE;
|
|
goto start;
|
|
}
|
|
case LP8_STATE_MEASURE:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
|
|
while(get_ready_state() != 1){
|
|
delay(10); //blocking, there is nothing else to do while measuring anyway
|
|
i++;
|
|
if(i >= 25){ //timeout after 250ms
|
|
if(diag) {
|
|
Serial.println("read_tout!");
|
|
}
|
|
sensor.error = LP8_ERROR_MEASURE_SIGNAL_RDY_TIMEOUT;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
}
|
|
i = 0;
|
|
|
|
sensor.tx_buffer[0] = MODBUS_ADDR;
|
|
sensor.tx_buffer[1] = MODBUS_READ;
|
|
sensor.tx_buffer[2] = 0x00;
|
|
sensor.tx_buffer[3] = 0x80;
|
|
sensor.tx_buffer[4] = 0x2c;
|
|
uint16_t crc16 = calculate_crc16(sensor.tx_buffer, 5);
|
|
sensor.tx_buffer[5] = crc16;
|
|
sensor.tx_buffer[6] = crc16 >> 8;
|
|
|
|
length = 7;
|
|
|
|
Serial1.write(sensor.tx_buffer, length);
|
|
delay(75); //need time to process transmission
|
|
|
|
sensor.state = LP8_STATE_MEASURE_READ;
|
|
}
|
|
case LP8_STATE_MEASURE_READ:
|
|
{
|
|
if(diag) {
|
|
Serial.println(sensor.state);
|
|
}
|
|
while(1) {
|
|
rxbuf = Serial1.read();
|
|
sensor.rx_buffer[i] = rxbuf;
|
|
i++;
|
|
if(i > 49){
|
|
break;
|
|
}
|
|
}
|
|
if(diag) {
|
|
Serial.println("read_resp");
|
|
}
|
|
i = 0;
|
|
|
|
tca_set_port(0xee); //turn off vbb
|
|
|
|
if(sensor.rx_buffer[0] != MODBUS_ADDR){
|
|
sensor.error = LP8_ERROR_MEASURE_READ_DEVICE_ADDRESS;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if(sensor.rx_buffer[1] != sensor.tx_buffer[1]){
|
|
sensor.error = LP8_ERROR_MEASURE_READ_COMMAND;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if(calculate_crc16(sensor.rx_buffer, 49) != 0){
|
|
if(diag) {
|
|
Serial.println("bad_recv_crc");
|
|
}
|
|
sensor.error = LP8_ERROR_MEASURE_READ_CRC;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if(diag) {
|
|
Serial.print("error0: ");
|
|
Serial.println(sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS0]);
|
|
Serial.print("error1: ");
|
|
Serial.println(sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS1]);
|
|
}
|
|
|
|
|
|
if (sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS0] == 32) {
|
|
sensor.error = LP8_ERROR_MEASURE_READ_OOR;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if (sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS1] == 4) {
|
|
sensor.error = LP8_ERROR_MEASURE_READ_STATUS1_ADC;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if (sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS1] == 2) {
|
|
sensor.error = LP8_ERROR_MEASURE_READ_STATUS1_VCAP2;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
if (sensor.rx_buffer[_BC_LP8_RX_ERROR_STATUS1] == 1) {
|
|
sensor.error = LP8_ERROR_MEASURE_READ_STATUS1_VCAP1;
|
|
sensor.state = LP8_STATE_ERROR;
|
|
goto start;
|
|
}
|
|
|
|
// memcpy(sensor.sensor_state, sensor.rx_buffer[4], 23);
|
|
if(diag) {
|
|
Serial.println("save_state");
|
|
}
|
|
while(i < 24) {
|
|
sensor.sensor_state[i] = sensor.rx_buffer[4 + i];
|
|
i++;
|
|
}
|
|
|
|
sensor.first_measurement_done = true;
|
|
|
|
sensor.concentration = (int16_t) sensor.rx_buffer[RX_CONC] << 8;
|
|
sensor.concentration |= (int16_t) sensor.rx_buffer[RX_CONC + 1];
|
|
|
|
sensor.valid = (sensor.concentration >= 0) && (sensor.concentration < 10000);
|
|
|
|
// tca_set_port(0xee);
|
|
sensor.state = LP8_STATE_READY;
|
|
return;
|
|
|
|
}
|
|
default:
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
int16_t get_co2_concentration(uint16_t pressure) {
|
|
|
|
sensor.pressure = pressure;
|
|
measure();
|
|
|
|
if(sensor.valid){
|
|
return(sensor.concentration);
|
|
}
|
|
else {
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
bool tca_set_port(uint8_t port) {
|
|
|
|
Wire.beginTransmission(TCA_ADDR);
|
|
Wire.write(TCA_REG_CONFIG);
|
|
Wire.write(port);
|
|
Wire.endTransmission();
|
|
|
|
return(true);
|
|
}
|
|
|
|
bool tca_set_direction(uint8_t dir) {
|
|
Wire.beginTransmission(TCA_ADDR);
|
|
Wire.write(TCA_REG_OUTPUT_PORT);
|
|
Wire.write(dir);
|
|
Wire.endTransmission();
|
|
|
|
return(true);
|
|
}
|
|
|
|
uint8_t get_ready_state() {
|
|
byte state;
|
|
byte rdyval;
|
|
|
|
Wire.beginTransmission(TCA_ADDR);
|
|
Wire.write(TCA_REG_INPUT_PORT);
|
|
Wire.endTransmission();
|
|
|
|
Wire.requestFrom(TCA_ADDR, 1);
|
|
state = Wire.read();
|
|
|
|
rdyval = ((state >> (uint8_t) TCA_RDY_PIN) & 0x01);
|
|
return(rdyval);
|
|
}
|
|
|
|
static uint16_t calculate_crc16(uint8_t *buffer, uint8_t length) {
|
|
uint16_t crc16;
|
|
|
|
for (crc16 = 0xffff; length != 0; length--, buffer++) {
|
|
crc16 ^= *buffer;
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((crc16 & 1) != 0) {
|
|
crc16 >>= 1;
|
|
crc16 ^= 0xa001;
|
|
}
|
|
else {
|
|
crc16 >>= 1;
|
|
}
|
|
}
|
|
}
|
|
return crc16;
|
|
} |