Skip to content

Commit 170b896

Browse files
committed
Add BSEC sensor support on Host side
1 parent 89f816e commit 170b896

File tree

7 files changed

+160
-12
lines changed

7 files changed

+160
-12
lines changed

examples/BSEC/BSEC.ino

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* This sketch shows how an arduino board can act as a host for nicla.
3+
* An host board can configure the sensors of nicla and then read their values.
4+
* The host board should be connected to nicla through the eslov connector.
5+
*
6+
* In this example, the BSEC sensor is enabled and its
7+
* values are periodically read and then printed to the serial channel
8+
*
9+
* NOTE: if Nicla is used as a Shield on top of a MKR board,
10+
* please use BHY2Host.begin(false, NICLA_AS_SHIELD)
11+
*/
12+
13+
#include "Arduino.h"
14+
#include "Arduino_BHY2Host.h"
15+
16+
SensorBSEC bsec(SENSOR_ID_BSEC);
17+
18+
void setup()
19+
{
20+
// debug port
21+
Serial.begin(115200);
22+
while(!Serial);
23+
24+
BHY2Host.begin();
25+
26+
bsec.begin();
27+
}
28+
29+
void loop()
30+
{
31+
static auto printTime = millis();
32+
BHY2Host.update();
33+
34+
if (millis() - printTime >= 1000) {
35+
printTime = millis();
36+
Serial.println(bsec.toString());
37+
}
38+
}

src/Arduino_BHY2Host.h

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "sensors/SensorOrientation.h"
1010
#include "sensors/SensorXYZ.h"
1111
#include "sensors/SensorQuaternion.h"
12+
#include "sensors/SensorBSEC.h"
1213
#include "sensors/SensorActivity.h"
1314
#include "sensors/Sensor.h"
1415

src/sensors/DataParser.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,34 @@ void DataParser::parseQuaternion(SensorDataPacket& data, DataQuaternion& vector,
2424
vector.accuracy = data.getUint16(8) * scaleFactor;
2525
}
2626

27+
void DataParser::parseBSEC(SensorDataPacket& data, DataBSEC& vector) {
28+
const float SCALE_BSEC_BVOC_EQ = 0.01f;
29+
const float SCALE_BSEC_COMP_T = 1.0f / 256;
30+
const float SCALE_BSEC_COMP_H = 1.0f / 500;
31+
32+
vector.iaq = data.getUint16(0);
33+
vector.iaq_s = data.getUint16(2);
34+
vector.b_voc_eq = data.getUint16(4) * SCALE_BSEC_BVOC_EQ; //b-VOC-eq in the FIFO frame is scaled up by 100
35+
vector.co2_eq = data.getUint24(6);
36+
vector.accuracy = data.getUint8(9);
37+
vector.comp_t = data.getInt16(10) * SCALE_BSEC_COMP_T;
38+
vector.comp_h = data.getUint16(12) * SCALE_BSEC_COMP_H;
39+
vector.comp_g = (uint32_t)(data.getFloat(14));
40+
}
41+
42+
void DataParser::parseBSECLegacy(SensorDataPacket& data, DataBSEC& vector) {
43+
vector.comp_t = data.getFloat(0);
44+
vector.comp_h = data.getFloat(4);
45+
//note that: SENSOR_DATA_FIXED_LENGTH is defined as 10 by default,
46+
//so all the fields below are 0 unless it's redefined to 29 and above
47+
vector.comp_g = (uint32_t)(data.getFloat(8));
48+
vector.iaq = (uint16_t)(data.getFloat(12));
49+
vector.iaq_s = (uint16_t)(data.getFloat(16));
50+
vector.co2_eq = (uint32_t)data.getFloat(20);
51+
vector.b_voc_eq = data.getFloat(24);
52+
vector.accuracy = data.getUint8(28);
53+
}
54+
2755
void DataParser::parseData(SensorDataPacket& data, float& value, float scaleFactor, SensorPayload format) {
2856
uint8_t id = data.sensorId;
2957
switch (format) {

src/sensors/DataParser.h

+25
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,37 @@ struct DataQuaternion {
4646
}
4747
};
4848

49+
struct DataBSEC {
50+
uint16_t iaq; //iaq value for regular use case
51+
uint16_t iaq_s; //iaq value for stationary use cases
52+
float b_voc_eq; //breath VOC equivalent (ppm)
53+
uint32_t co2_eq; //CO2 equivalent (ppm) [400,]
54+
float comp_t; //compensated temperature (celcius)
55+
float comp_h; //compensated humidity
56+
uint32_t comp_g; //compensated gas resistance (Ohms)
57+
uint8_t accuracy; //accuracy level: [0-3]
58+
59+
String toString() {
60+
return (String)("BSEC output values - iaq: " + String(iaq)
61+
+ " iaq_s: " + String(iaq_s)
62+
+ " b_voc_eq: " + String(b_voc_eq, 2)
63+
+ " co2_eq: " + String(co2_eq)
64+
+ " accuracy: " + String(accuracy)
65+
+ " comp_t: " + String(comp_t, 2)
66+
+ " comp_h: " + String(comp_h, 2)
67+
+ " comp_g: " + String(comp_g)
68+
+ "\n");
69+
}
70+
};
71+
4972
class DataParser {
5073
public:
5174
static void parse3DVector(SensorDataPacket& data, DataXYZ& vector);
5275
static void parseEuler(SensorDataPacket& data, DataOrientation& vector);
5376
static void parseEuler(SensorDataPacket& data, DataOrientation& vector, float scaleFactor);
5477
static void parseQuaternion(SensorDataPacket& data, DataQuaternion& vector, float scaleFactor);
78+
static void parseBSEC(SensorDataPacket& data, DataBSEC& vector);
79+
static void parseBSECLegacy(SensorDataPacket& data, DataBSEC& vector);
5580
static void parseData(SensorDataPacket& data, float& value, float scaleFactor, SensorPayload format);
5681
static void parseActivity(SensorDataPacket& data, uint16_t value);
5782
};

src/sensors/SensorBSEC.h

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef SENSOR_BSEC_H_
2+
#define SENSOR_BSEC_H_
3+
4+
#include "SensorClass.h"
5+
6+
7+
class SensorBSEC : public SensorClass {
8+
public:
9+
SensorBSEC() {}
10+
SensorBSEC(uint8_t id) : SensorClass(id), _data() {}
11+
12+
/*
13+
BSEC sensor frames are:
14+
- 18 bytes for BSEC new format (SID=115 SENSOR_ID_BSEC_LEGACY)
15+
- 29 bytes for legacy format (SID=171 SENSOR_ID_BSEC)
16+
If the default size of SENSOR_DATA_FIXED_LENGTH is used (10 bytes), some fields of BSEC might be always 0.
17+
Enlarge SENSOR_DATA_FIXED_LENGTH to see all the fields of the BSEC sensor.
18+
For the new format (SID=115), if the compensated values (comp_t, comp_h, comp_g) are not important,
19+
keep SENSOR_DATA_FIXED_LENGTH to the default value (10) to save bandwidth.
20+
*/
21+
uint16_t iaq() {return _data.iaq;}
22+
uint16_t iaq_s() {return _data.iaq_s;}
23+
float b_voc_eq() {return _data.b_voc_eq;}
24+
uint32_t co2_eq() {return _data.co2_eq;}
25+
uint8_t accuracy() {return _data.accuracy;}
26+
float comp_t() {return _data.comp_t;}
27+
float comp_h() {return _data.comp_h;}
28+
uint32_t comp_g() {return _data.comp_g;}
29+
30+
31+
void setData(SensorDataPacket &data)
32+
{
33+
if (_id == SENSOR_ID_BSEC ) {
34+
DataParser::parseBSEC(data, _data);
35+
} else if (_id == SENSOR_ID_BSEC_LEGACY) {
36+
DataParser::parseBSECLegacy(data, _data);
37+
}
38+
}
39+
40+
String toString()
41+
{
42+
return _data.toString();
43+
}
44+
45+
private:
46+
DataBSEC _data;
47+
};
48+
#endif

src/sensors/SensorID.h

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum SensorID {
5252
SENSOR_ID_GYRO_BIAS_WU = 92, /* Gyroscope offset wake up */
5353
SENSOR_ID_MAG_BIAS_WU = 93, /* Magnetometer offset wake up */
5454
SENSOR_ID_STD_WU = 94, /* Step detector wake up */
55+
SENSOR_ID_BSEC = 115, /* BSEC 1.x output */
5556
SENSOR_ID_TEMP = 128, /* Temperature */
5657
SENSOR_ID_BARO = 129, /* Barometer */
5758
SENSOR_ID_HUM = 130, /* Humidity */
@@ -74,6 +75,7 @@ enum SensorID {
7475
SENSOR_ID_PROX = 147, /* Proximity */
7576
SENSOR_ID_LIGHT_WU = 148, /* Light wake up */
7677
SENSOR_ID_PROX_WU = 149, /* Proximity wake up */
78+
SENSOR_ID_BSEC_LEGACY = 171, /* BSEC 1.x output (legacy, deprecated) */
7779
DEBUG_DATA_EVENT = 250, /* Binary or string debug data */
7880
TIMESTAMP_SMALL_DELTA = 251, /* Incremental time change from previous read */
7981
TIMESTAMP_SMALL_DELTA_WU = 245, /* Incremental time change from previous read wake up */

src/sensors/SensorTypes.h

+18-12
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ struct __attribute__((packed)) SensorDataPacket {
2525
float result = 0;
2626
uint8_t length = sizeof(result);
2727
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
28-
length = SENSOR_DATA_FIXED_LENGTH - index;
28+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
2929
}
30-
memcpy(&result, &data[index], sizeof(result));
30+
if (length > 0)
31+
memcpy(&result, &data[index], length);
3132
return result;
3233
}
3334

@@ -42,29 +43,32 @@ struct __attribute__((packed)) SensorDataPacket {
4243
uint16_t result = 0;
4344
uint8_t length = sizeof(result);
4445
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
45-
length = SENSOR_DATA_FIXED_LENGTH - index;
46+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
4647
}
47-
memcpy(&result, &data[index], length);
48+
if (length > 0)
49+
memcpy(&result, &data[index], length);
4850
return result;
4951
}
5052

5153
uint32_t getUint24(uint8_t index) {
5254
uint32_t result = 0;
5355
uint8_t length = 3;
5456
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
55-
length = SENSOR_DATA_FIXED_LENGTH - index;
57+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
5658
}
57-
memcpy(&result, &data[index], length);
59+
if (length > 0)
60+
memcpy(&result, &data[index], length);
5861
return result;
5962
}
6063

6164
uint32_t getUint32(uint8_t index) {
6265
uint32_t result = 0;
6366
uint8_t length = sizeof(result);
6467
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
65-
length = SENSOR_DATA_FIXED_LENGTH - index;
68+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
6669
}
67-
memcpy(&result, &data[index], length);
70+
if (length > 0)
71+
memcpy(&result, &data[index], length);
6872
return result;
6973
}
7074

@@ -79,19 +83,21 @@ struct __attribute__((packed)) SensorDataPacket {
7983
int16_t result = 0;
8084
uint8_t length = sizeof(result);
8185
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
82-
length = SENSOR_DATA_FIXED_LENGTH - index;
86+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
8387
}
84-
memcpy(&result, &data[index], length);
88+
if (length > 0)
89+
memcpy(&result, &data[index], length);
8590
return result;
8691
}
8792

8893
int32_t getInt32(uint8_t index) {
8994
int32_t result = 0;
9095
uint8_t length = sizeof(result);
9196
if (index + length > SENSOR_DATA_FIXED_LENGTH) {
92-
length = SENSOR_DATA_FIXED_LENGTH - index;
97+
length = SENSOR_DATA_FIXED_LENGTH > index ? SENSOR_DATA_FIXED_LENGTH - index : 0;
9398
}
94-
memcpy(&result, &data[index], length);
99+
if (length > 0)
100+
memcpy(&result, &data[index], length);
95101
return result;
96102
}
97103
};

0 commit comments

Comments
 (0)