Skip to content

Commit

Permalink
Merge pull request #32 from arduino/bsec+examples
Browse files Browse the repository at this point in the history
Add support for Bsec sensors
  • Loading branch information
giulcioffi committed Oct 13, 2021
2 parents 7afd70c + 938ad1d commit fb192b7
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/Arduino_BHY2.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "sensors/SensorOrientation.h"
#include "sensors/SensorXYZ.h"
#include "sensors/SensorQuaternion.h"
#include "sensors/SensorBSEC.h"
#include "sensors/SensorActivity.h"
#include "sensors/Sensor.h"

Expand Down
31 changes: 30 additions & 1 deletion src/sensors/DataParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ void DataParser::parseQuaternion(SensorDataPacket& data, DataQuaternion& vector)
vector.accuracy = data.getUint16(8);
}

void DataParser::parseBSEC(SensorDataPacket& data, DataBSEC& vector) {
const float SCALE_BSEC_BVOC_EQ = 0.01f;
const float SCALE_BSEC_COMP_T = 1.0f / 256;
const float SCALE_BSEC_COMP_H = 1.0f / 500;

vector.iaq = data.getUint16(0);
vector.iaq_s = data.getUint16(2);
vector.b_voc_eq = data.getUint16(4) * SCALE_BSEC_BVOC_EQ; //b-VOC-eq in the FIFO frame is scaled up by 100
vector.co2_eq = data.getUint24(6);
vector.accuracy = data.getUint8(9);
vector.comp_t = data.getInt16(10) * SCALE_BSEC_COMP_T;
vector.comp_h = data.getUint16(12) * SCALE_BSEC_COMP_H;
vector.comp_g = (uint32_t)(data.getFloat(14));
}

void DataParser::parseBSECLegacy(SensorDataPacket& data, DataBSEC& vector) {
vector.comp_t = data.getFloat(0);
vector.comp_h = data.getFloat(4);
//note that: SENSOR_DATA_FIXED_LENGTH is defined as 10 by default,
//so all the fields below are 0 unless it's redefined to 29 and above
vector.comp_g = (uint32_t)(data.getFloat(8));
vector.iaq = (uint16_t)(data.getFloat(12));
vector.iaq_s = (uint16_t)(data.getFloat(16));
vector.co2_eq = (uint32_t)data.getFloat(20);
vector.b_voc_eq = data.getFloat(24);
vector.accuracy = data.getUint8(28);
}


void DataParser::parseData(SensorDataPacket& data, float& value, float scaleFactor, SensorPayload format) {
uint8_t id = data.sensorId;
switch (format) {
Expand Down Expand Up @@ -58,4 +87,4 @@ void DataParser::parseData(SensorDataPacket& data, float& value, float scaleFact

void DataParser::parseActivity(SensorDataPacket& data, uint16_t& value) {
value = data.getUint16(0);
}
}
36 changes: 31 additions & 5 deletions src/sensors/DataParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ struct DataOrientation {
float roll;

String toString() {
return (String)("Orientation values - heading: " + String(heading, 3)
+ " pitch: " + String(pitch, 3)
return (String)("Orientation values - heading: " + String(heading, 3)
+ " pitch: " + String(pitch, 3)
+ " roll: " + String(roll, 3) + "\n");
}
};
Expand All @@ -39,19 +39,45 @@ struct DataQuaternion {
String toString() {
return (String)("Quaternion values - X: " + String(x)
+ " Y: " + String(y)
+ " Z: " + String(z)
+ " W: " + String(w)
+ " Accuracy: " + String(accuracy)
+ " Z: " + String(z)
+ " W: " + String(w)
+ " Accuracy: " + String(accuracy)
+ "\n");
}
};

struct DataBSEC {
uint16_t iaq; //iaq value for regular use case
uint16_t iaq_s; //iaq value for stationary use cases
float b_voc_eq; //breath VOC equivalent (ppm)
uint32_t co2_eq; //CO2 equivalent (ppm) [400,]
float comp_t; //compensated temperature (celcius)
float comp_h; //compensated humidity
uint32_t comp_g; //compensated gas resistance (Ohms)
uint8_t accuracy; //accuracy level: [0-3]

String toString() {
return (String)("BSEC output values - iaq: " + String(iaq)
+ " iaq_s: " + String(iaq_s)
+ " b_voc_eq: " + String(b_voc_eq, 2)
+ " co2_eq: " + String(co2_eq)
+ " accuracy: " + String(accuracy)
+ " comp_t: " + String(comp_t, 2)
+ " comp_h: " + String(comp_h, 2)
+ " comp_g: " + String(comp_g)
+ "\n");
}
};


class DataParser {
public:
static void parse3DVector(SensorDataPacket& data, DataXYZ& vector);
static void parseEuler(SensorDataPacket& data, DataOrientation& vector);
static void parseEuler(SensorDataPacket& data, DataOrientation& vector, float scaleFactor);
static void parseQuaternion(SensorDataPacket& data, DataQuaternion& vector);
static void parseBSEC(SensorDataPacket& data, DataBSEC& vector);
static void parseBSECLegacy(SensorDataPacket& data, DataBSEC& vector);
static void parseData(SensorDataPacket& data, float& value, float scaleFactor, SensorPayload format);
static void parseActivity(SensorDataPacket& data, uint16_t& value);
};
Expand Down
48 changes: 48 additions & 0 deletions src/sensors/SensorBSEC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef SENSOR_BSEC_H_
#define SENSOR_BSEC_H_

#include "SensorClass.h"


class SensorBSEC : public SensorClass {
public:
SensorBSEC() {}
SensorBSEC(uint8_t id) : SensorClass(id), _data() {}

/*
BSEC sensor frames are:
- 18 bytes for BSEC new format (SID=115 SENSOR_ID_BSEC_LEGACY)
- 29 bytes for legacy format (SID=171 SENSOR_ID_BSEC)
If the default size of SENSOR_DATA_FIXED_LENGTH is used (10 bytes), some fields of BSEC might be always 0.
Enlarge SENSOR_DATA_FIXED_LENGTH to see all the fields of the BSEC sensor.
For the new format (SID=115), if the compensated values (comp_t, comp_h, comp_g) are not important,
keep SENSOR_DATA_FIXED_LENGTH to the default value (10) to save bandwidth.
*/
uint16_t iaq() {return _data.iaq;}
uint16_t iaq_s() {return _data.iaq_s;}
float b_voc_eq() {return _data.b_voc_eq;}
uint32_t co2_eq() {return _data.co2_eq;}
uint8_t accuracy() {return _data.accuracy;}
float comp_t() {return _data.comp_t;}
float comp_h() {return _data.comp_h;}
uint32_t comp_g() {return _data.comp_g;}


void setData(SensorDataPacket &data)
{
if (_id == SENSOR_ID_BSEC ) {
DataParser::parseBSEC(data, _data);
} else if (_id == SENSOR_ID_BSEC_LEGACY) {
DataParser::parseBSECLegacy(data, _data);
}
}

String toString()
{
return _data.toString();
}

private:
DataBSEC _data;
};
#endif
2 changes: 2 additions & 0 deletions src/sensors/SensorID.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum SensorID {
SENSOR_ID_GYRO_BIAS_WU = 92, /* Gyroscope offset wake up */
SENSOR_ID_MAG_BIAS_WU = 93, /* Magnetometer offset wake up */
SENSOR_ID_STD_WU = 94, /* Step detector wake up */
SENSOR_ID_BSEC = 115, /* BSEC 1.x output */
SENSOR_ID_TEMP = 128, /* Temperature */
SENSOR_ID_BARO = 129, /* Barometer */
SENSOR_ID_HUM = 130, /* Humidity */
Expand All @@ -74,6 +75,7 @@ enum SensorID {
SENSOR_ID_PROX = 147, /* Proximity */
SENSOR_ID_LIGHT_WU = 148, /* Light wake up */
SENSOR_ID_PROX_WU = 149, /* Proximity wake up */
SENSOR_ID_BSEC_LEGACY = 171, /* BSEC 1.x output (legacy, deprecated) */
DEBUG_DATA_EVENT = 250, /* Binary or string debug data */
TIMESTAMP_SMALL_DELTA = 251, /* Incremental time change from previous read */
TIMESTAMP_SMALL_DELTA_WU = 245, /* Incremental time change from previous read wake up */
Expand Down
31 changes: 19 additions & 12 deletions src/sensors/SensorTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ struct __attribute__((packed)) SensorDataPacket {
float result = 0;
uint8_t length = sizeof(result);
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
//to safe guard against overflow
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], sizeof(result));
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}

Expand All @@ -42,29 +44,32 @@ struct __attribute__((packed)) SensorDataPacket {
uint16_t result = 0;
uint8_t length = sizeof(result);
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], length);
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}

uint32_t getUint24(uint8_t index) {
uint32_t result = 0;
uint8_t length = 3;
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], length);
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}

uint32_t getUint32(uint8_t index) {
uint32_t result = 0;
uint8_t length = sizeof(result);
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], length);
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}

Expand All @@ -79,19 +84,21 @@ struct __attribute__((packed)) SensorDataPacket {
int16_t result = 0;
uint8_t length = sizeof(result);
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], length);
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}

int32_t getInt32(uint8_t index) {
int32_t result = 0;
uint8_t length = sizeof(result);
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
length = SENSOR_DATA_FIXED_LENGTH - index;
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
}
memcpy(&result, &data[index], length);
if (length > 0)
memcpy(&result, &data[index], length);
return result;
}
};
Expand Down

0 comments on commit fb192b7

Please sign in to comment.