diff --git a/LICENSE b/LICENSE index 9add70f..a4c72ef 100644 --- a/LICENSE +++ b/LICENSE @@ -2,9 +2,9 @@ The binaries and includes for the core BSEC library in this repository are licen under the Software license agreement described in the link https://www.bosch-sensortec.com/media/boschsensortec/downloads/bsec/2017-07-17_clickthrough_license_terms_environmentalib_sw_clean.pdf -The Arduino wrapper and BME680 Sensor API are licensed under the following license. +The Arduino wrapper and BME68x Sensor API are licensed under the following license. -Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. BSD-3-Clause @@ -15,12 +15,12 @@ modification, are permitted provided that the following conditions are met: notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -33,4 +33,4 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md index 465c08e..042ce24 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## About BSEC -Bosch Sensortec Environmental Cluster (BSEC) Software v1.4.8.0 released on July 8th, 2020 +Bosch Sensortec Environmental Cluster (BSEC) Software v1.4.9.2 released on June 13th, 2022 The BSEC fusion library has been conceptualized to provide a higher-level signal processing and fusion for the BME680. The library receives compensated sensor values from the sensor API. It processes the BME680 signals to provide the requested sensor outputs. diff --git a/examples/basic/basic.ino b/examples/basic/basic.ino index 3f61b1f..3495795 100644 --- a/examples/basic/basic.ino +++ b/examples/basic/basic.ino @@ -12,32 +12,36 @@ String output; // Entry point for the example void setup(void) { + /* Initializes the Serial communication */ Serial.begin(115200); - Wire.begin(); - - iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); + delay(1000); + pinMode(LED_BUILTIN, OUTPUT); + iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire); output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); Serial.println(output); checkIaqSensorStatus(); - bsec_virtual_sensor_t sensorList[10] = { - BSEC_OUTPUT_RAW_TEMPERATURE, - BSEC_OUTPUT_RAW_PRESSURE, - BSEC_OUTPUT_RAW_HUMIDITY, - BSEC_OUTPUT_RAW_GAS, + bsec_virtual_sensor_t sensorList[13] = { BSEC_OUTPUT_IAQ, BSEC_OUTPUT_STATIC_IAQ, BSEC_OUTPUT_CO2_EQUIVALENT, BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, + BSEC_OUTPUT_RAW_TEMPERATURE, + BSEC_OUTPUT_RAW_PRESSURE, + BSEC_OUTPUT_RAW_HUMIDITY, + BSEC_OUTPUT_RAW_GAS, + BSEC_OUTPUT_STABILIZATION_STATUS, + BSEC_OUTPUT_RUN_IN_STATUS, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + BSEC_OUTPUT_GAS_PERCENTAGE }; - iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); + iaqSensor.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_LP); checkIaqSensorStatus(); // Print the header - output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%], Static IAQ, CO2 equivalent, breath VOC equivalent"; + output = "Timestamp [ms], IAQ, IAQ accuracy, Static IAQ, CO2 equivalent, breath VOC equivalent, raw temp[°C], pressure [hPa], raw relative humidity [%], gas [Ohm], Stab Status, run in status, comp temp[°C], comp humidity [%], gas percentage"; Serial.println(output); } @@ -46,19 +50,24 @@ void loop(void) { unsigned long time_trigger = millis(); if (iaqSensor.run()) { // If new data is available + digitalWrite(LED_BUILTIN, LOW); output = String(time_trigger); + output += ", " + String(iaqSensor.iaq); + output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.staticIaq); + output += ", " + String(iaqSensor.co2Equivalent); + output += ", " + String(iaqSensor.breathVocEquivalent); output += ", " + String(iaqSensor.rawTemperature); output += ", " + String(iaqSensor.pressure); output += ", " + String(iaqSensor.rawHumidity); output += ", " + String(iaqSensor.gasResistance); - output += ", " + String(iaqSensor.iaq); - output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.stabStatus); + output += ", " + String(iaqSensor.runInStatus); output += ", " + String(iaqSensor.temperature); output += ", " + String(iaqSensor.humidity); - output += ", " + String(iaqSensor.staticIaq); - output += ", " + String(iaqSensor.co2Equivalent); - output += ", " + String(iaqSensor.breathVocEquivalent); + output += ", " + String(iaqSensor.gasPercentage); Serial.println(output); + digitalWrite(LED_BUILTIN, HIGH); } else { checkIaqSensorStatus(); } @@ -67,26 +76,26 @@ void loop(void) // Helper function definitions void checkIaqSensorStatus(void) { - if (iaqSensor.status != BSEC_OK) { - if (iaqSensor.status < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor.status); + if (iaqSensor.bsecStatus != BSEC_OK) { + if (iaqSensor.bsecStatus < BSEC_OK) { + output = "BSEC error code : " + String(iaqSensor.bsecStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BSEC warning code : " + String(iaqSensor.status); + output = "BSEC warning code : " + String(iaqSensor.bsecStatus); Serial.println(output); } } - if (iaqSensor.bme680Status != BME680_OK) { - if (iaqSensor.bme680Status < BME680_OK) { - output = "BME680 error code : " + String(iaqSensor.bme680Status); + if (iaqSensor.bme68xStatus != BME68X_OK) { + if (iaqSensor.bme68xStatus < BME68X_OK) { + output = "BME68X error code : " + String(iaqSensor.bme68xStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BME680 warning code : " + String(iaqSensor.bme680Status); + output = "BME68X warning code : " + String(iaqSensor.bme68xStatus); Serial.println(output); } } diff --git a/examples/basic_config_state/basic_config_state.ino b/examples/basic_config_state/basic_config_state.ino index edc5ef5..83a6a95 100644 --- a/examples/basic_config_state/basic_config_state.ino +++ b/examples/basic_config_state/basic_config_state.ino @@ -17,6 +17,7 @@ const uint8_t bsec_config_iaq[] = { #include "config/generic_33v_3s_4d/bsec_iaq.txt" }; + #define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day // Helper functions declarations @@ -35,11 +36,11 @@ String output; // Entry point for the example void setup(void) { - EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); // 1st address for the length + EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); Serial.begin(115200); - Wire.begin(); - - iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); + delay(1000); + pinMode(LED_BUILTIN, OUTPUT); + iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire); output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); Serial.println(output); checkIaqSensorStatus(); @@ -49,21 +50,27 @@ void setup(void) loadState(); - bsec_virtual_sensor_t sensorList[7] = { + bsec_virtual_sensor_t sensorList[13] = { + BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_STATIC_IAQ, + BSEC_OUTPUT_CO2_EQUIVALENT, + BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_RAW_GAS, - BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_STABILIZATION_STATUS, + BSEC_OUTPUT_RUN_IN_STATUS, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + BSEC_OUTPUT_GAS_PERCENTAGE }; - iaqSensor.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP); + iaqSensor.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_LP); checkIaqSensorStatus(); // Print the header - output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%]"; + output = "Timestamp [ms], IAQ, IAQ accuracy, Static IAQ, CO2 equivalent, breath VOC equivalent, raw temp[°C], pressure [hPa], raw relative humidity [%], gas [Ohm], Stab Status, run in status, comp temp[°C], comp humidity [%], gas percentage"; Serial.println(output); } @@ -72,16 +79,24 @@ void loop(void) { unsigned long time_trigger = millis(); if (iaqSensor.run()) { // If new data is available + digitalWrite(LED_BUILTIN, LOW); output = String(time_trigger); + output += ", " + String(iaqSensor.iaq); + output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.staticIaq); + output += ", " + String(iaqSensor.co2Equivalent); + output += ", " + String(iaqSensor.breathVocEquivalent); output += ", " + String(iaqSensor.rawTemperature); output += ", " + String(iaqSensor.pressure); output += ", " + String(iaqSensor.rawHumidity); output += ", " + String(iaqSensor.gasResistance); - output += ", " + String(iaqSensor.iaq); - output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.stabStatus); + output += ", " + String(iaqSensor.runInStatus); output += ", " + String(iaqSensor.temperature); output += ", " + String(iaqSensor.humidity); + output += ", " + String(iaqSensor.gasPercentage); Serial.println(output); + digitalWrite(LED_BUILTIN, HIGH); updateState(); } else { checkIaqSensorStatus(); @@ -91,30 +106,29 @@ void loop(void) // Helper function definitions void checkIaqSensorStatus(void) { - if (iaqSensor.status != BSEC_OK) { - if (iaqSensor.status < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor.status); + if (iaqSensor.bsecStatus != BSEC_OK) { + if (iaqSensor.bsecStatus < BSEC_OK) { + output = "BSEC error code : " + String(iaqSensor.bsecStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BSEC warning code : " + String(iaqSensor.status); + output = "BSEC warning code : " + String(iaqSensor.bsecStatus); Serial.println(output); } } - if (iaqSensor.bme680Status != BME680_OK) { - if (iaqSensor.bme680Status < BME680_OK) { - output = "BME680 error code : " + String(iaqSensor.bme680Status); + if (iaqSensor.bme68xStatus != BME68X_OK) { + if (iaqSensor.bme68xStatus < BME68X_OK) { + output = "BME68X error code : " + String(iaqSensor.bme68xStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BME680 warning code : " + String(iaqSensor.bme680Status); + output = "BME68X warning code : " + String(iaqSensor.bme68xStatus); Serial.println(output); } } - iaqSensor.status = BSEC_OK; } void errLeds(void) @@ -153,14 +167,14 @@ void loadState(void) void updateState(void) { bool update = false; - /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */ if (stateUpdateCounter == 0) { + /* First state update when IAQ accuracy is >= 3 */ if (iaqSensor.iaqAccuracy >= 3) { update = true; stateUpdateCounter++; } } else { - /* Update every STATE_SAVE_PERIOD milliseconds */ + /* Update every STATE_SAVE_PERIOD minutes */ if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) { update = true; stateUpdateCounter++; @@ -181,4 +195,4 @@ void updateState(void) EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE); EEPROM.commit(); } -} \ No newline at end of file +} diff --git a/examples/basic_config_state_ULP_LP/basic_config_state_ULP_LP.ino b/examples/basic_config_state_ULP_LP/basic_config_state_ULP_LP.ino index 638fb26..f1feeff 100644 --- a/examples/basic_config_state_ULP_LP/basic_config_state_ULP_LP.ino +++ b/examples/basic_config_state_ULP_LP/basic_config_state_ULP_LP.ino @@ -17,6 +17,7 @@ const uint8_t bsec_config_iaq[] = { #include "config/generic_33v_3s_4d/bsec_iaq.txt" }; + #define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day // Helper functions declarations @@ -37,9 +38,9 @@ void setup(void) { EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); // 1st address for the length Serial.begin(115200); - Wire.begin(); - - iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); + delay(1000); + pinMode(LED_BUILTIN, OUTPUT); + iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire); output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); Serial.println(output); checkIaqSensorStatus(); @@ -50,26 +51,25 @@ void setup(void) loadState(); bsec_virtual_sensor_t sensorList1[2] = { - BSEC_OUTPUT_RAW_GAS, BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_RAW_GAS }; iaqSensor.updateSubscription(sensorList1, 2, BSEC_SAMPLE_RATE_ULP); - checkIaqSensorStatus(); bsec_virtual_sensor_t sensorList2[5] = { BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY }; iaqSensor.updateSubscription(sensorList2, 5, BSEC_SAMPLE_RATE_LP); checkIaqSensorStatus(); // Print the header - output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%]"; + output = "Timestamp [ms], IAQ, IAQ accuracy, raw temp[°C], pressure [hPa], raw relative humidity [%], gas [Ohm], comp temp[°C], comp humidity [%]"; Serial.println(output); } @@ -78,16 +78,18 @@ void loop(void) { unsigned long time_trigger = millis(); if (iaqSensor.run()) { // If new data is available + digitalWrite(LED_BUILTIN, LOW); output = String(time_trigger); + output += ", " + String(iaqSensor.iaq); + output += ", " + String(iaqSensor.iaqAccuracy); output += ", " + String(iaqSensor.rawTemperature); output += ", " + String(iaqSensor.pressure); output += ", " + String(iaqSensor.rawHumidity); output += ", " + String(iaqSensor.gasResistance); - output += ", " + String(iaqSensor.iaq); - output += ", " + String(iaqSensor.iaqAccuracy); output += ", " + String(iaqSensor.temperature); output += ", " + String(iaqSensor.humidity); Serial.println(output); + digitalWrite(LED_BUILTIN, HIGH); updateState(); } else { checkIaqSensorStatus(); @@ -97,26 +99,26 @@ void loop(void) // Helper function definitions void checkIaqSensorStatus(void) { - if (iaqSensor.status != BSEC_OK) { - if (iaqSensor.status < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor.status); + if (iaqSensor.bsecStatus != BSEC_OK) { + if (iaqSensor.bsecStatus < BSEC_OK) { + output = "BSEC error code : " + String(iaqSensor.bsecStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BSEC warning code : " + String(iaqSensor.status); + output = "BSEC warning code : " + String(iaqSensor.bsecStatus); Serial.println(output); } } - if (iaqSensor.bme680Status != BME680_OK) { - if (iaqSensor.bme680Status < BME680_OK) { - output = "BME680 error code : " + String(iaqSensor.bme680Status); + if (iaqSensor.bme68xStatus != BME68X_OK) { + if (iaqSensor.bme68xStatus < BME68X_OK) { + output = "BME68X error code : " + String(iaqSensor.bme68xStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BME680 warning code : " + String(iaqSensor.bme680Status); + output = "BME68X warning code : " + String(iaqSensor.bme68xStatus); Serial.println(output); } } diff --git a/examples/basic_config_state_multi/basic_config_state_multi.ino b/examples/basic_config_state_multi/basic_config_state_multi.ino deleted file mode 100644 index 3ff8e0f..0000000 --- a/examples/basic_config_state_multi/basic_config_state_multi.ino +++ /dev/null @@ -1,235 +0,0 @@ -#include -#include "bsec.h" -/* Configure the BSEC library with information about the sensor - 18v/33v = Voltage at Vdd. 1.8V or 3.3V - 3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP - 4d/28d = Operating age of the sensor in days - generic_18v_3s_4d - generic_18v_3s_28d - generic_18v_300s_4d - generic_18v_300s_28d - generic_33v_3s_4d - generic_33v_3s_28d - generic_33v_300s_4d - generic_33v_300s_28d -*/ -const uint8_t bsec_config_iaq[] = { -#include "config/generic_33v_3s_4d/bsec_iaq.txt" -}; - -#define STATE_SAVE_PERIOD UINT32_C(300000) // 360 minutes - 4 times a day -#define N_SENSORS 2 - -// Helper functions declarations -void checkIaqSensorStatus(void); -void errLeds(void); -void loadState(void); -void updateState(void); - -// Create objects of the class Bsec -Bsec iaqSensor1, iaqSensor2; -uint8_t bsecState1[BSEC_MAX_STATE_BLOB_SIZE], bsecState2[BSEC_MAX_STATE_BLOB_SIZE]; -uint16_t stateUpdateCounter = 0; - -String output; - -// Entry point for the example -void setup(void) -{ - EEPROM.begin((N_SENSORS * BSEC_MAX_STATE_BLOB_SIZE) + 1); // 1st address for the length of one state - Serial.begin(115200); - Wire.begin(); - - iaqSensor1.begin(BME680_I2C_ADDR_PRIMARY, Wire); - iaqSensor2.begin(BME680_I2C_ADDR_SECONDARY, Wire); - output = "\nBSEC library version " + String(iaqSensor1.version.major) + "." + String(iaqSensor1.version.minor) + "." + String(iaqSensor1.version.major_bugfix) + "." + String(iaqSensor1.version.minor_bugfix); - Serial.println(output); - checkIaqSensorStatus(); - - iaqSensor1.setConfig(bsec_config_iaq); - iaqSensor2.setConfig(bsec_config_iaq); - checkIaqSensorStatus(); - - loadState(); - - bsec_virtual_sensor_t sensorList[7] = { - BSEC_OUTPUT_RAW_TEMPERATURE, - BSEC_OUTPUT_RAW_PRESSURE, - BSEC_OUTPUT_RAW_HUMIDITY, - BSEC_OUTPUT_RAW_GAS, - BSEC_OUTPUT_IAQ, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, - }; - - iaqSensor1.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP); - iaqSensor2.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_LP); - checkIaqSensorStatus(); - - // Print the header - output = "Sensor, Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%]"; - Serial.println(output); -} - -// Function that is looped forever -void loop(void) -{ - unsigned long time_trigger = millis(); - if (iaqSensor1.run()) { // If new data is available - output = "1, " + String(time_trigger); - output += ", " + String(iaqSensor1.rawTemperature); - output += ", " + String(iaqSensor1.pressure); - output += ", " + String(iaqSensor1.rawHumidity); - output += ", " + String(iaqSensor1.gasResistance); - output += ", " + String(iaqSensor1.iaq); - output += ", " + String(iaqSensor1.iaqAccuracy); - output += ", " + String(iaqSensor1.temperature); - output += ", " + String(iaqSensor1.humidity); - Serial.println(output); - updateState(); - } else { - checkIaqSensorStatus(); - } - - time_trigger = millis(); - if (iaqSensor2.run()) { // If new data is available - output = "2, " + String(time_trigger); - output += ", " + String(iaqSensor2.rawTemperature); - output += ", " + String(iaqSensor2.pressure); - output += ", " + String(iaqSensor2.rawHumidity); - output += ", " + String(iaqSensor2.gasResistance); - output += ", " + String(iaqSensor2.iaq); - output += ", " + String(iaqSensor2.iaqAccuracy); - output += ", " + String(iaqSensor2.temperature); - output += ", " + String(iaqSensor2.humidity); - Serial.println(output); - updateState(); - } else { - checkIaqSensorStatus(); - } -} - -// Helper function definitions -void checkIaqSensorStatus(void) -{ - if (iaqSensor1.status != BSEC_OK) { - if (iaqSensor1.status < BSEC_OK) { - output = "BSEC1 error code : " + String(iaqSensor1.status); - Serial.println(output); - for (;;) - errLeds(); /* Halt in case of failure */ - } else { - output = "BSEC warning code : " + String(iaqSensor1.status); - Serial.println(output); - } - } - - if (iaqSensor1.bme680Status != BME680_OK) { - if (iaqSensor1.bme680Status < BME680_OK) { - output = "BME6801 error code : " + String(iaqSensor1.bme680Status); - Serial.println(output); - for (;;) - errLeds(); /* Halt in case of failure */ - } else { - output = "BME680 warning code : " + String(iaqSensor1.bme680Status); - Serial.println(output); - } - } - iaqSensor1.status = BSEC_OK; - - if (iaqSensor2.status != BSEC_OK) { - if (iaqSensor2.status < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor2.status); - Serial.println(output); - for (;;) - errLeds(); /* Halt in case of failure */ - } else { - output = "BSEC warning code : " + String(iaqSensor2.status); - Serial.println(output); - } - } - - if (iaqSensor2.bme680Status != BME680_OK) { - if (iaqSensor2.bme680Status < BME680_OK) { - output = "BME680 error code : " + String(iaqSensor2.bme680Status); - Serial.println(output); - for (;;) - errLeds(); /* Halt in case of failure */ - } else { - output = "BME680 warning code : " + String(iaqSensor2.bme680Status); - Serial.println(output); - } - } - iaqSensor2.status = BSEC_OK; -} - -void errLeds(void) -{ - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, HIGH); - delay(100); - digitalWrite(LED_BUILTIN, LOW); - delay(100); -} - -void loadState(void) -{ - if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE) { - // Existing state in EEPROM - Serial.println("Reading state from EEPROM"); - - for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) { - bsecState1[i] = EEPROM.read(i + 1); - bsecState2[i] = EEPROM.read(i + 1 + BSEC_MAX_STATE_BLOB_SIZE); - Serial.println(String(bsecState1[i], HEX) + ", " + String(bsecState2[i], HEX)); - } - - iaqSensor1.setState(bsecState1); - iaqSensor2.setState(bsecState2); - checkIaqSensorStatus(); - } else { - // Erase the EEPROM with zeroes - Serial.println("Erasing EEPROM"); - - for (uint16_t i = 0; i < (N_SENSORS * BSEC_MAX_STATE_BLOB_SIZE) + 1; i++) { - EEPROM.write(i, 0); - } - - EEPROM.commit(); - } -} - -void updateState(void) -{ - bool update = false; - /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */ - if (stateUpdateCounter == 0) { - if ((iaqSensor1.iaqAccuracy >= 3) || (iaqSensor2.iaqAccuracy >= 3)) { - update = true; - stateUpdateCounter++; - } - } else { - /* Update every STATE_SAVE_PERIOD milliseconds */ - if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) { - update = true; - stateUpdateCounter++; - } - } - - if (update) { - iaqSensor1.getState(bsecState1); - iaqSensor2.getState(bsecState2); - checkIaqSensorStatus(); - - Serial.println("Writing state(s) to EEPROM"); - - for (uint16_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE ; i++) { - EEPROM.write(i + 1, bsecState1[i]); - EEPROM.write(i + 1 + BSEC_MAX_STATE_BLOB_SIZE, bsecState2[i]); - Serial.println(String(bsecState1[i], HEX) + ", " + String(bsecState2[i], HEX)); - } - - EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE); - EEPROM.commit(); - } -} \ No newline at end of file diff --git a/examples/basic_config_state_ulp_plus/basic_config_state_ulp_plus.ino b/examples/basic_config_state_ulp_plus/basic_config_state_ulp_plus.ino index 2e891d9..60ada86 100644 --- a/examples/basic_config_state_ulp_plus/basic_config_state_ulp_plus.ino +++ b/examples/basic_config_state_ulp_plus/basic_config_state_ulp_plus.ino @@ -17,6 +17,7 @@ const uint8_t bsec_config_iaq[] = { #include "config/generic_33v_3s_4d/bsec_iaq.txt" }; + #define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day // Helper functions declarations @@ -24,6 +25,7 @@ void checkIaqSensorStatus(void); void errLeds(void); void loadState(void); void updateState(void); +void ICACHE_RAM_ATTR ulp_plus_button_press(); // Create an object of the class Bsec Bsec iaqSensor; @@ -39,13 +41,13 @@ void setup(void) { EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1); // 1st address for the length Serial.begin(115200); - Wire.begin(); - + delay(1000); + pinMode(LED_BUILTIN, OUTPUT); /* Setup button interrupt to trigger ULP plus */ pinMode(2, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(2), ulp_plus_button_press, FALLING); - iaqSensor.begin(BME680_I2C_ADDR_PRIMARY, Wire); + iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire); output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); Serial.println(output); checkIaqSensorStatus(); @@ -55,21 +57,27 @@ void setup(void) loadState(); - bsec_virtual_sensor_t sensorList[7] = { + bsec_virtual_sensor_t sensorList[13] = { + BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_STATIC_IAQ, + BSEC_OUTPUT_CO2_EQUIVALENT, + BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, BSEC_OUTPUT_RAW_TEMPERATURE, BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_RAW_GAS, - BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_STABILIZATION_STATUS, + BSEC_OUTPUT_RUN_IN_STATUS, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + BSEC_OUTPUT_GAS_PERCENTAGE }; - iaqSensor.updateSubscription(sensorList, 7, BSEC_SAMPLE_RATE_ULP); + iaqSensor.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_ULP); checkIaqSensorStatus(); // Print the header - output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%]"; + output = "Timestamp [ms], IAQ, IAQ accuracy, Static IAQ, CO2 equivalent, breath VOC equivalent, raw temp[°C], pressure [hPa], raw relative humidity [%], gas [Ohm], Stab Status, run in status, comp temp[°C], comp humidity [%], gas percentage"; Serial.println(output); } @@ -78,16 +86,24 @@ void loop(void) { unsigned long time_trigger = millis(); if (iaqSensor.run()) { // If new data is available + digitalWrite(LED_BUILTIN, LOW); output = String(time_trigger); + output += ", " + String(iaqSensor.iaq); + output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.staticIaq); + output += ", " + String(iaqSensor.co2Equivalent); + output += ", " + String(iaqSensor.breathVocEquivalent); output += ", " + String(iaqSensor.rawTemperature); output += ", " + String(iaqSensor.pressure); output += ", " + String(iaqSensor.rawHumidity); output += ", " + String(iaqSensor.gasResistance); - output += ", " + String(iaqSensor.iaq); - output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.stabStatus); + output += ", " + String(iaqSensor.runInStatus); output += ", " + String(iaqSensor.temperature); output += ", " + String(iaqSensor.humidity); + output += ", " + String(iaqSensor.gasPercentage); Serial.println(output); + digitalWrite(LED_BUILTIN, HIGH); updateState(); } else { checkIaqSensorStatus(); @@ -97,26 +113,26 @@ void loop(void) // Helper function definitions void checkIaqSensorStatus(void) { - if (iaqSensor.status != BSEC_OK) { - if (iaqSensor.status < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor.status); + if (iaqSensor.bsecStatus != BSEC_OK) { + if (iaqSensor.bsecStatus < BSEC_OK) { + output = "BSEC error code : " + String(iaqSensor.bsecStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BSEC warning code : " + String(iaqSensor.status); + output = "BSEC warning code : " + String(iaqSensor.bsecStatus); Serial.println(output); } } - if (iaqSensor.bme680Status != BME680_OK) { - if (iaqSensor.bme680Status < BME680_OK) { - output = "BME680 error code : " + String(iaqSensor.bme680Status); + if (iaqSensor.bme68xStatus != BME68X_OK) { + if (iaqSensor.bme68xStatus < BME68X_OK) { + output = "BME68X error code : " + String(iaqSensor.bme68xStatus); Serial.println(output); for (;;) errLeds(); /* Halt in case of failure */ } else { - output = "BME680 warning code : " + String(iaqSensor.bme680Status); + output = "BME68X warning code : " + String(iaqSensor.bme68xStatus); Serial.println(output); } } @@ -159,13 +175,13 @@ void updateState(void) { bool update = false; if (stateUpdateCounter == 0) { - /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */ + /* First state update when IAQ accuracy is >= 3 */ if (iaqSensor.iaqAccuracy >= 3) { update = true; stateUpdateCounter++; } } else { - /* Update every STATE_SAVE_PERIOD milliseconds */ + /* Update every STATE_SAVE_PERIOD minutes */ if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) { update = true; stateUpdateCounter++; @@ -193,7 +209,7 @@ void updateState(void) @return none */ -void ulp_plus_button_press() +void ICACHE_RAM_ATTR ulp_plus_button_press() { /* We call bsec_update_subscription() in order to instruct BSEC to perform an extra measurement at the next possible time slot diff --git a/examples/esp32DeepSleep/README.md b/examples/esp32DeepSleep/README.md new file mode 100644 index 0000000..fb5712e --- /dev/null +++ b/examples/esp32DeepSleep/README.md @@ -0,0 +1,5 @@ +The compensated temperature, compensated humidity, IAQ & Static IAQ are not supported in this example code +because bsec expects the time to be ticking but during deepsleep the time resets to 0. + +To overcome this the sleep duration can be added to the millis and passed to bsec from the example code. +Changes in bsec.c is also needed for this to work. \ No newline at end of file diff --git a/examples/esp32DeepSleep/esp32DeepSleep.ino b/examples/esp32DeepSleep/esp32DeepSleep.ino index 8a4a6d4..6904165 100644 --- a/examples/esp32DeepSleep/esp32DeepSleep.ino +++ b/examples/esp32DeepSleep/esp32DeepSleep.ino @@ -31,12 +31,8 @@ bsec_virtual_sensor_t sensor_list[] = { BSEC_OUTPUT_RAW_PRESSURE, BSEC_OUTPUT_RAW_HUMIDITY, BSEC_OUTPUT_RAW_GAS, - BSEC_OUTPUT_IAQ, - BSEC_OUTPUT_STATIC_IAQ, BSEC_OUTPUT_CO2_EQUIVALENT, BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, }; int64_t GetTimestamp() { @@ -46,18 +42,18 @@ int64_t GetTimestamp() { } bool CheckSensor() { - if (sensor.status < BSEC_OK) { - LOG("BSEC error, status %d!", sensor.status); + if (sensor.bsecStatus < BSEC_OK) { + LOG("BSEC error, status %d!", sensor.bsecStatus); return false;; - } else if (sensor.status > BSEC_OK) { - LOG("BSEC warning, status %d!", sensor.status); + } else if (sensor.bsecStatus > BSEC_OK) { + LOG("BSEC warning, status %d!", sensor.bsecStatus); } - if (sensor.bme680Status < BME680_OK) { - LOG("Sensor error, bme680_status %d!", sensor.bme680Status); + if (sensor.bme68xStatus < BME68X_OK) { + LOG("Sensor error, bme680_status %d!", sensor.bme68xStatus); return false; - } else if (sensor.bme680Status > BME680_OK) { - LOG("Sensor warning, status %d!", sensor.bme680Status); + } else if (sensor.bme68xStatus > BME68X_OK) { + LOG("Sensor warning, status %d!", sensor.bme68xStatus); } return true; @@ -114,12 +110,10 @@ void setup() { } void loop() { - if (sensor.run(GetTimestamp())) { + if (sensor.run()) { LOG("Temperature raw %.2f compensated %.2f", sensor.rawTemperature, sensor.temperature); LOG("Humidity raw %.2f compensated %.2f", sensor.rawHumidity, sensor.humidity); LOG("Pressure %.2f kPa", sensor.pressure / 1000); - LOG("IAQ %.0f accuracy %d", sensor.iaq, sensor.iaqAccuracy); - LOG("Static IAQ %.0f accuracy %d", sensor.staticIaq, sensor.staticIaqAccuracy); LOG("Gas resistance %.2f kOhm", sensor.gasResistance / 1000); sensor_state_time = GetTimestamp(); @@ -128,7 +122,7 @@ void loop() { LOG("Saved state to RTC memory at %lld", sensor_state_time); CheckSensor(); - uint64_t time_us = ((sensor.nextCall - GetTimestamp()) * 1000) - esp_timer_get_time(); + uint64_t time_us = (sensor.nextCall * 1000) - esp_timer_get_time(); LOG("Deep sleep for %llu ms. BSEC next call at %llu ms.", time_us / 1000, sensor.nextCall); esp_sleep_enable_timer_wakeup(time_us); esp_deep_sleep_start(); diff --git a/examples/octopus_demo/OLED_featherwing_display.cpp b/examples/octopus_demo/OLED_featherwing_display.cpp new file mode 100644 index 0000000..9860d28 --- /dev/null +++ b/examples/octopus_demo/OLED_featherwing_display.cpp @@ -0,0 +1,95 @@ +/** Global Library includes */ + +/** Local Library includes */ + +#include "OLED_featherwing_display.h" + +/** Global variables */ +ImageList image_list[NUMBER_OF_IMAGES]; + +// Create an SSD1306 display object +Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire); + +/** Function definitions */ + +/********************************************************************************/ +void initialize_display() +{ + // Decode logos from uint32_t x 32 (32x32) to uint8_t x 128 + decodeLogo(image_list[0].image, logo_bosch); + decodeLogo(image_list[1].image, logo_temp); + decodeLogo(image_list[2].image, logo_pres); + decodeLogo(image_list[3].image, logo_hum); + decodeLogo(image_list[4].image, logo_gas); + // Initialize the OLED display + display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_I2C_ADDR); // initialize with the I2C addr 0x3C (for the 128x32) + display.clearDisplay(); + display.display(); +} + +/********************************************************************************/ +void display_print_string(String text, uint8_t x_axis, uint8_t y_axis, uint8_t text_size) +{ + display.clearDisplay(); + display.setTextSize(text_size); + display.setTextColor(WHITE); + display.setCursor(x_axis, y_axis); + display.println(text); + display.display(); +} +/********************************************************************************/ + +void display_print_multi_string(String line1, uint8_t x_axis1, uint8_t y_axis1, uint8_t text_size1, String line2_0, + String line2, + uint8_t x_axis2, uint8_t y_axis2, uint8_t text_size2) +{ + display.clearDisplay(); + display.setTextSize(text_size1); + display.setTextColor(WHITE); + display.setCursor(x_axis1, y_axis1); + display.println(line1); + + display.setTextSize(text_size2); + display.setTextColor(WHITE); + display.setCursor(x_axis2, y_axis2); + display.println(line2); + + display.setTextSize(1); + display.setTextColor(WHITE); + display.setCursor(110, 16); + display.println(" A"); + display.setCursor(110, 24); + display.println(line2_0); + + display.display(); +} + +/********************************************************************************/ +void display_bosch_logo(String fwVersion) +{ + display.clearDisplay(); + display.drawBitmap(0, 0, image_list[0].image, 32, 32, WHITE); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(40, 10); + display.println("BOSCH"); + display.setTextSize(1); + display.setCursor(40, 00); + display.println(fwVersion); + display.display(); +} + +void display_print_img_string(String label, String value, uint8_t bmp, uint8_t label_size, uint8_t value_size) +{ + display.clearDisplay(); + display.drawBitmap(0, 0, image_list[bmp].image, 32, 32, WHITE); + display.setTextSize(label_size); + display.setTextColor(WHITE); + display.setCursor(40, 0); + display.println(label); + display.setTextSize(value_size); + display.setCursor(40, 20); + display.println(value); + display.display(); +} + diff --git a/examples/octopus_demo/OLED_featherwing_display.h b/examples/octopus_demo/OLED_featherwing_display.h new file mode 100644 index 0000000..65eecea --- /dev/null +++ b/examples/octopus_demo/OLED_featherwing_display.h @@ -0,0 +1,69 @@ +/** Global Library includes */ + +#ifndef __OLED_FEATHERWING_DISPLAY_H_ +#define __OLED_FEATHERWING_DISPLAY_H_ + +#include +#include +#include + +/** Local Library includes */ + +#include "logos.h" + +/** Defines and consts */ +#define NUMBER_OF_IMAGES 5u +#define DISPLAY_I2C_ADDR 0x3c + +/** Structs and enums */ + +struct ImageList +{ + uint8_t image[128]; +}; + +extern ImageList image_list[NUMBER_OF_IMAGES]; + +/** Function declarations */ + +/** + * @brief Function used to initialize local objects for images with + * global consts from logos.h file + */ +void initialize_display(); + +/** + * @brief Function used to clear display and print the input string + * @param text [input] Input string that needs to be printed on display. + */ +void display_print_string(String text, uint8_t x_axis, uint8_t y_axis, uint8_t text_size); + +/** + * @brief Function used to clear display and print the input string + * @param text [input] Input string that needs to be printed on display. + */ +void display_print_multi_string(String line1, uint8_t x_axis1, uint8_t y_axis1, uint8_t text_size1, + String line2_0, + String line2, uint8_t x_axis2, uint8_t y_axis2, uint8_t text_size2); + +/** + * @brief Function used to display BOSCH logo on OLED display. + * @param fwVersion [input] Firmware version that needs to be printed on OLED Display + */ +void display_bosch_logo(String fwVersion); + +/** + * @brief Function used to clear display and print input label and string based on bmp Index. + * @param label [input] Title which needs to be printed on display + * @param value [input] Value which needs to be printed on display + * @param bmp [input] Index number corresponding to bmp files + * @param label_size [input] Size of label string to be printed on OLED display + * @param value_size [input] Size of value string to be printed on OLED display + */ +void display_print_img_string(String label, String value, uint8_t bmp, uint8_t label_size, uint8_t value_size); + +/** Global variables */ + +extern Adafruit_SSD1306 display; + +#endif diff --git a/examples/octopus_demo/README.md b/examples/octopus_demo/README.md new file mode 100644 index 0000000..b5477b9 --- /dev/null +++ b/examples/octopus_demo/README.md @@ -0,0 +1,6 @@ +Install Adafruit SSD1306, Adafruit GFX Library & Adafruit BusIO from the Arduino Library Manager + +Versions used for testing +Adafruit SSD1306 version 2.3.1 +Adafruit GFX Library version 1.9.0 +Adafruit BusIO version 1.3.3 \ No newline at end of file diff --git a/examples/octopus_demo/logos.cpp b/examples/octopus_demo/logos.cpp new file mode 100644 index 0000000..f0e3bfe --- /dev/null +++ b/examples/octopus_demo/logos.cpp @@ -0,0 +1,23 @@ +#include "logos.h" + +void decodeLogo(uint8_t *bitmap, const uint32_t *logo) +{ + uint8_t i, j; + + for (i = 0; i < 128; i++) + bitmap[i] = 0; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 32; j++) + { + bitmap[(4 * j) + i] = (((logo[i * 8] & 1 << j) >> j) << 7) | + (((logo[(i * 8) + 1] & 1 << j) >> j) << 6) | + (((logo[(i * 8) + 2] & 1 << j) >> j) << 5) | + (((logo[(i * 8) + 3] & 1 << j) >> j) << 4) | + (((logo[(i * 8) + 4] & 1 << j) >> j) << 3) | + (((logo[(i * 8) + 5] & 1 << j) >> j) << 2) | + (((logo[(i * 8) + 6] & 1 << j) >> j) << 1) | + (((logo[(i * 8) + 7] & 1 << j) >> j)); + } + } +} diff --git a/examples/octopus_demo/logos.h b/examples/octopus_demo/logos.h new file mode 100644 index 0000000..90b4012 --- /dev/null +++ b/examples/octopus_demo/logos.h @@ -0,0 +1,61 @@ +#ifndef __LOGOS_H_ +#define __LOGOS_H_ + +#include + +void decodeLogo(uint8_t *bitmap, const uint32_t *logo); + +const uint8_t lockBmp[32] = { +B00000000, B00000000, +B00000000, B00000000, +B00000011, B11000000, +B00001100, B00110000, +B00011000, B00011000, +B00011000, B00011000, +B00011000, B00011000, +B00011000, B00011000, +B00111111, B11111100, +B00111110, B01111100, +B00111100, B00111100, +B00111100, B00111100, +B00111110, B01111100, +B00111110, B01111100, +B00111111, B11111100, +B00011111, B11111000 }; + +const uint32_t logo_bosch[32] = { 0x00000000, 0x000FF000, 0x003FFC00, + 0x00F00F00, 0x03C003C0, 0x071FF8E0, 0x067FFE60, 0x0CE00730, 0x19C00398, + 0x3B8001DC, 0x33FFFFCC, 0x33FFFFCC, 0x60381C06, 0x60381C06, 0x60381C06, + 0x60381C06, 0x60381C06, 0x60381C06, 0x60381C06, 0x60381C06, 0x33FFFFCC, + 0x33FFFFCC, 0x3B8001DC, 0x19C00398, 0x0CE00730, 0x067FFE60, 0x071FF8E0, + 0x03C003C0, 0x00F00F00, 0x003FFC00, 0x000FF000, 0x00000000 }; + +const uint32_t logo_temp[32] = { 0x00000000, 0x00000000, 0x00001000, 0x00001000, + 0x00011080, 0x00011080, 0x000113E0, 0x00011080, 0x00011080, 0x00001000, + 0x03C01000, 0x07E01000, 0x1C3FFFFC, 0x193FFFFE, 0x3B80100E, 0x3904522E, + 0x1C3FFFFE, 0x1FFFFFFC, 0x08301000, 0x10101000, 0x20081000, 0x40441000, + 0x40441000, 0x47C41000, 0x40441000, 0x40441000, 0x20081000, 0x10101000, + 0x08201000, 0x07C00000, 0x00000000 }; + +const uint32_t logo_hum[32] = { 0x00000000, 0x00000000, 0x01FF0000, 0x03FFC000, + 0x0701F000, 0x0E007800, 0x1C7C1C00, 0x38E00E00, 0x71800700, 0x73000380, + 0x730001C0, 0x720000E0, 0x72000070, 0x72001FF0, 0x710071E0, 0x38006670, + 0x1FF0CC18, 0x0C09980C, 0x10059006, 0x23E3900C, 0x21A1C818, 0x42E16070, + 0x400131C0, 0x43E11F00, 0x40810000, 0x20810000, 0x23E20000, 0x10040000, + 0x0C080000, 0x03F00000, 0x00000000, 0x00000000 }; + +const uint32_t logo_pres[32] = { 0x00000000, 0x00000400, 0x00000400, 0x1F1FC400, + 0x31BFE404, 0x64FFF008, 0x6E607C10, 0x64303F80, 0x30181C40, 0x180C0C20, + 0x0E060C20, 0x07030C20, 0x03C18C2E, 0x03E0DC20, 0x03B87840, 0x038C3F80, + 0x03871C00, 0x0381CE40, 0x07C07320, 0x08201990, 0x10101EC0, 0x20081BE0, + 0x400418F0, 0x4FE47838, 0x4124F000, 0x4124C000, 0x40C7C000, 0x200F8000, + 0x101F0000, 0x08200000, 0x07C00000, 0x00000000 }; + +const uint32_t logo_gas[32] = { 0x00000000, 0x038000F8, 0x0440018C, 0x08200306, + 0x08200202, 0x08600202, 0x04900202, 0x0389F706, 0x0047F98C, 0x002F10F8, + 0x001E2080, 0x00382100, 0x00381380, 0x00380F80, 0x003E0380, 0x00390380, + 0x00108380, 0x00208700, 0x07E11E80, 0x0833FC40, 0x101DF238, 0x23880124, + 0x444400C2, 0x48240082, 0x49240082, 0x4F240044, 0x41040038, 0x20080000, + 0x10100000, 0x08200000, 0x07C00000, 0x00000000 }; + +#endif diff --git a/examples/octopus_demo/octopus_demo.ino b/examples/octopus_demo/octopus_demo.ino new file mode 100644 index 0000000..e7436df --- /dev/null +++ b/examples/octopus_demo/octopus_demo.ino @@ -0,0 +1,642 @@ +/** + * octopus_demo.cpp + * + * Functionalities: Demo application to showcase the functionality of BME680 by configuring + * the sensor in different modes of operation (ULP, LP and CONT) for different + * data update rates at user level which in turn provides access to various use case. + */ + +/** Global Library includes */ +#include "bsec.h" +#include + +/* Configure the BSEC library with information about the sensor + 18v/33v = Voltage at Vdd. 1.8V or 3.3V + 3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP + 4d/28d = Operating age of the sensor in days + generic_18v_3s_4d + generic_18v_3s_28d + generic_18v_300s_4d + generic_18v_300s_28d + generic_33v_3s_4d + generic_33v_3s_28d + generic_33v_300s_4d + generic_33v_300s_28d +*/ +const uint8_t bsec_config_iaq[] = { +#include "config/generic_33v_3s_4d/bsec_iaq.txt" +}; + +/** Local Library includes */ + +#include "OLED_featherwing_display.h" +/** Defines and consts */ + +// #define DEBUG_MODE + +#define BUTTON_A 0 /**< Pin connected to OLED Featherwing on Octopus board */ +#define BUTTON_C 2 /**< Pin connected to OLED Featherwing on Octopus board */ + +/* Save all 3 modes of operating parameters in EEPROM */ + +#define EEPROM_NUMBER_OF_REGIONS 3u +#define EEPROM_BYTES_PER_REGION (BSEC_MAX_STATE_BLOB_SIZE + 1) /* This value indicates max bytes per region including region identifier length*/ + +#define BSEC_EEPROM_ULP_IDENTIFIER 0u +#define BSEC_EEPROM_ULP_REGION_START 1u +#define BSEC_EEPROM_ULP_REGION_END (EEPROM_BYTES_PER_REGION) + +#define BSEC_EEPROM_LP_IDENTIFIER BSEC_EEPROM_ULP_REGION_END +#define BSEC_EEPROM_LP_REGION_START (BSEC_EEPROM_LP_IDENTIFIER + 1) +#define BSEC_EEPROM_LP_REGION_END (BSEC_EEPROM_LP_REGION_START + EEPROM_BYTES_PER_REGION) + +#define BSEC_EEPROM_CONT_IDENTIFIER BSEC_EEPROM_LP_REGION_END +#define BSEC_EEPROM_CONT_REGION_START (BSEC_EEPROM_CONT_IDENTIFIER + 1) +#define BSEC_EEPROM_CONT_REGION_END (BSEC_EEPROM_CONT_REGION_START + EEPROM_BYTES_PER_REGION) + +#define EEPROM_TOTAL_ALLOCATED_BYTES (BSEC_EEPROM_CONT_REGION_END) + +/** Structs and enums */ +typedef enum +{ + ULP_MODE_SCREEN_OFF = 1, + LP_MODE_SCREEN_ON = 2, + CONT_MODE_BREATH = 3 +} OPERATING_MODES; + +/** Global variables */ + +OPERATING_MODES operating_mode = LP_MODE_SCREEN_ON; +static float previous_IAQ = 0; +static uint8_t previous_IAQ_acc = 0; + +uint8_t bsec_state_ulp[BSEC_MAX_STATE_BLOB_SIZE] = { 0 }; +uint8_t bsec_state_lp[BSEC_MAX_STATE_BLOB_SIZE] = { 0 }; +uint8_t bsec_state_cont[BSEC_MAX_STATE_BLOB_SIZE] = { 0 }; + +bsec_virtual_sensor_t sensorList[5] = { + BSEC_OUTPUT_RAW_TEMPERATURE, + BSEC_OUTPUT_RAW_PRESSURE, + BSEC_OUTPUT_RAW_HUMIDITY, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY +}; + +bsec_virtual_sensor_t sensorIAQ[2] = { + BSEC_OUTPUT_RAW_GAS, + BSEC_OUTPUT_IAQ +}; + +String output; + +// Create a Bsec object +Bsec iaqSensor; + +/** Function declarations */ +void ICACHE_RAM_ATTR button_press_A(void); +void ICACHE_RAM_ATTR button_press_C(void); +bool button_A_intr = false; +bool button_C_intr = false; +void eeprom_initialize(void); +void configure_sensor_mode(OPERATING_MODES operating_mode); +void report_status(void); +void err_leds(void); +void load_state(OPERATING_MODES operating_mode); +void update_state(OPERATING_MODES operating_mode); + +/** + * @brief Setup function for peripherals and other controls of MCU. + * + */ +void setup() +{ + /* Initialize Serial Terminal */ + Serial.begin(115200); + /* Temporary place holder for firmware version */ + String bsecVersion; + /* Initialize I2C */ + Wire.begin(); + + /* Required delay for OLED display to get sufficient time after power on. */ + delay(1000); + pinMode(LED_BUILTIN, OUTPUT); + Serial.print("\nInitializing OLED Display"); + /* Initialize OLED display */ + initialize_display(); + + display_print_string("Initializing...", 0, 0, 1); + + Serial.print("\nInitializing on board EEPROM"); + eeprom_initialize(); + + Serial.print("\nInitializing buttons"); + /* Setup button interrupt to trigger scanning mode */ + pinMode(BUTTON_A, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(BUTTON_A), button_press_A, RISING); + pinMode(BUTTON_C, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(BUTTON_C), button_press_C, RISING); + Serial.print("\nInitializing Sensor connected on I2C Address: "); + Serial.println(BME68X_I2C_ADDR_LOW); + + /* Sensor and Library initialization */ + configure_sensor_mode(operating_mode); + + /* Report loaded library on serial terminal */ + bsecVersion = "BSEC V" + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); + Serial.println(bsecVersion); + + // Print the header + output = "Timestamp [ms], raw temp[°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, comp temp[°C], comp humidity [%], operating mode, bme68x status, bsec status"; + Serial.println(output); + + display_bosch_logo(bsecVersion); +} + +/** + * @brief Arduino continuous looping function. + */ +void loop() +{ + String oled_output_line1, oled_output_line2_0, oled_output_line2; + if (iaqSensor.run()) + { + digitalWrite(LED_BUILTIN, LOW); + output = String(millis()); + output += ", " + String(iaqSensor.rawTemperature); + output += ", " + String(iaqSensor.pressure); + output += ", " + String(iaqSensor.rawHumidity); + output += ", " + String(iaqSensor.gasResistance); + output += ", " + String(iaqSensor.iaq); + output += ", " + String(iaqSensor.iaqAccuracy); + output += ", " + String(iaqSensor.temperature); + output += ", " + String(iaqSensor.humidity); + output += ", " + String(operating_mode); + output += ", " + String(iaqSensor.bme68xStatus); + output += ", " + String(iaqSensor.bsecStatus); + Serial.println(output); + digitalWrite(LED_BUILTIN, HIGH); + + /* Keep updating sensor state values in RAM based on mode of operation */ + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: + + iaqSensor.getState(bsec_state_ulp); + + /* Happens only during first time after power on */ + if (EEPROM.read(BSEC_EEPROM_ULP_IDENTIFIER) != BSEC_MAX_STATE_BLOB_SIZE) + { + update_state(ULP_MODE_SCREEN_OFF); + } + + oled_output_line2 = "Mode:ULP"; + break; + + case LP_MODE_SCREEN_ON: + + iaqSensor.getState(bsec_state_lp); + + /* Happens only during first time after power on */ + if (EEPROM.read(BSEC_EEPROM_LP_IDENTIFIER) != BSEC_MAX_STATE_BLOB_SIZE) + { + update_state(LP_MODE_SCREEN_ON); + } + oled_output_line2 = "Mode:LP"; + break; + + case CONT_MODE_BREATH: + + iaqSensor.getState(bsec_state_cont); + /* Happens only during first time after power on */ + if (EEPROM.read(BSEC_EEPROM_CONT_IDENTIFIER) != BSEC_MAX_STATE_BLOB_SIZE) + { + update_state(CONT_MODE_BREATH); + } + oled_output_line2 = "Mode:CONT"; + break; + + default: + break; + + } + + /* String handling segment for OLED display */ + if((iaqSensor.gasResistance == 0) && (iaqSensor.iaq == 0)) + { + oled_output_line1 = "IAQ:" + String(previous_IAQ, 2); + oled_output_line2_0 = " " + String(previous_IAQ_acc); + } + else + { + oled_output_line1 = "IAQ:" + String(iaqSensor.iaq, 2); + previous_IAQ = iaqSensor.iaq; + oled_output_line2_0 = " " + String(iaqSensor.iaqAccuracy); + previous_IAQ_acc = iaqSensor.iaqAccuracy; + } + + oled_output_line2 += " degC:" + + String(iaqSensor.temperature, 1) + + + "\nrH:" + + String(iaqSensor.humidity, 1) + + "% hPa:" + + String((iaqSensor.pressure / 100.0f), 1); + + display_print_multi_string(oled_output_line1, 0, 0, 2, oled_output_line2_0, + oled_output_line2, + 0, 16, 1); + + } + else{ + report_status(); + } + + /* Handle button press interrupt and trigger underlying functionality to switch modes */ + if (button_A_intr == true) + { + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: + + /* Update current mode i.e save current values from RAM to EEPROM for LP Mode. */ + update_state(operating_mode); + + /* Toggle operating mode. */ + operating_mode = LP_MODE_SCREEN_ON; + + /* Load settings for new mode from EEPROM to RAM */ + load_state(operating_mode); + + /* Configure sensor operation for updated mode. */ + configure_sensor_mode(operating_mode); + break; + + case LP_MODE_SCREEN_ON: + + /* Update current mode i.e save current values from RAM to EEPROM for LP Mode. */ + update_state(operating_mode); + + /* Toggle operating mode. */ + operating_mode = CONT_MODE_BREATH; + + /* Load settings for new mode from EEPROM to RAM */ + load_state(operating_mode); + + /* Configure sensor operation for updated mode. */ + configure_sensor_mode(operating_mode); + break; + + case CONT_MODE_BREATH: + + /* Reached End of button functionality for this mode. No more further toggling allowed. */ + /* Update current mode i.e save current values from RAM to EEPROM for CONT Mode. */ + operating_mode = CONT_MODE_BREATH; + update_state(operating_mode); + break; + + default: + break; + + } + button_A_intr = false; + } + + /* Handle button press interrupt and trigger underlying functionality to switch modes */ + if (button_C_intr) + { + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: + /* Reached End of button functionality for this mode. No more further toggling allowed. */ + /* Update current mode i.e save current values from RAM to EEPROM for ULP Mode. */ + /* Toggle operating mode. */ + operating_mode = ULP_MODE_SCREEN_OFF; + + update_state(operating_mode); + break; + + case LP_MODE_SCREEN_ON: + + /* Update current mode i.e save current values from RAM to EEPROM for LP Mode. */ + update_state(operating_mode); + + /* Toggle operating mode. */ + operating_mode = ULP_MODE_SCREEN_OFF; + + /* Load settings for new mode from EEPROM to RAM */ + load_state(operating_mode); + + /* Configure sensor operation for updated mode. */ + configure_sensor_mode(operating_mode); + break; + + case CONT_MODE_BREATH: + + /* Update current mode i.e save current values from RAM to EEPROM for CONT Mode. */ + update_state(operating_mode); + + /* Toggle operating mode. */ + operating_mode = LP_MODE_SCREEN_ON; + + /* Load settings for new mode from EEPROM to RAM */ + load_state(operating_mode); + + /* Configure sensor operation for updated mode. */ + configure_sensor_mode(operating_mode); + break; + + default: + break; + + } + button_C_intr = false; + } +} + +/** + * @brief Button click A Handler + * Toggle operation: ULP -> LP -> CONT(Breath Mode) + * + */ +void ICACHE_RAM_ATTR button_press_A(void) +{ + button_A_intr = true; +} + +/** + * @brief Button click C Handler + * Toggle operation: CONT(Breath Mode) -> LP -> ULP + * + */ +void ICACHE_RAM_ATTR button_press_C(void) +{ + button_C_intr = true; +} + +/** + * @brief Configuration of bme680 and bsec library can be done using this function. + * @param operating_mode[in] Mode of sensor operation. Can be chosen from the list below. + * -ULP_MODE_SCREEN_OFF + * -LP_MODE_SCREEN_ON + * -CONT_MODE_BREATH + */ +void configure_sensor_mode(OPERATING_MODES operating_mode) +{ +#ifdef DEBUG_MODE + Serial.print("\nConfiguring sensor mode: "); +#endif + /* Initialize BME68X sensor */ + iaqSensor.begin(BME68X_I2C_ADDR_LOW, Wire); + + // Set config + iaqSensor.setConfig(bsec_config_iaq); + + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: +#ifdef DEBUG_MODE + Serial.print("ULP Mode"); +#endif + iaqSensor.setState(bsec_state_ulp); + iaqSensor.updateSubscription(sensorList, 5, BSEC_SAMPLE_RATE_LP); + iaqSensor.updateSubscription(sensorIAQ, 2, BSEC_SAMPLE_RATE_ULP); + break; + + case LP_MODE_SCREEN_ON: +#ifdef DEBUG_MODE + Serial.print("LP Mode"); +#endif + iaqSensor.setState(bsec_state_lp); + iaqSensor.updateSubscription(sensorList, 5, BSEC_SAMPLE_RATE_CONT); + iaqSensor.updateSubscription(sensorIAQ, 2, BSEC_SAMPLE_RATE_LP); + break; + + case CONT_MODE_BREATH: +#ifdef DEBUG_MODE + Serial.print("CONT Mode"); +#endif + iaqSensor.setState(bsec_state_cont); + iaqSensor.updateSubscription(sensorList, 5, BSEC_SAMPLE_RATE_CONT); + iaqSensor.updateSubscription(sensorIAQ, 2, BSEC_SAMPLE_RATE_CONT); + break; + + default: + break; + + } +#ifdef DEBUG_MODE + Serial.print("\nUpdate subscription: "); + /* Report Sensor status on serial terminal */ + report_status(); + +#endif +} + +/** + * @brief Initializes EEPROM memory space and loads previously saved values + * @return void + */ +void eeprom_initialize(void) +{ + bsec_state_ulp[BSEC_MAX_STATE_BLOB_SIZE-1] = 10; + /* Initialize EEPROM Memory segment of ESP8266 */ + EEPROM.begin(EEPROM_TOTAL_ALLOCATED_BYTES); // 1st address for the length + + if ((EEPROM.read(BSEC_EEPROM_ULP_IDENTIFIER) == BSEC_MAX_STATE_BLOB_SIZE) || + (EEPROM.read(BSEC_EEPROM_LP_IDENTIFIER) == BSEC_MAX_STATE_BLOB_SIZE) + || + (EEPROM.read(BSEC_EEPROM_CONT_IDENTIFIER) == BSEC_MAX_STATE_BLOB_SIZE)) + { + Serial.print("\nSaved data found, loading previous EEPROM values "); + for (uint16_t array_index = 0; array_index < BSEC_MAX_STATE_BLOB_SIZE; array_index++) + { + bsec_state_ulp[array_index] = EEPROM.read(BSEC_EEPROM_ULP_REGION_START + array_index); + bsec_state_lp[array_index] = EEPROM.read(BSEC_EEPROM_LP_REGION_START + array_index); + bsec_state_cont[array_index] = EEPROM.read(BSEC_EEPROM_CONT_REGION_START + array_index); + } + } + else + { + Serial.print("\nFirst time flash. Erasing complete EEPROM"); + for (uint16_t i = 0; i < EEPROM_TOTAL_ALLOCATED_BYTES; i++) + EEPROM.write(i, 0); + + EEPROM.commit(); + + } +} + +/** + * @brief Save the values from RAM to appropriate memory location in EEPROM based on operating_mode + * @param operating_mode Defines the start EEPROM address for writing to EEPROM + * -ULP_MODE_SCREEN_OFF + * -LP_MODE_SCREEN_ON + * -CONT_MODE_BREATH + */ +void update_state(OPERATING_MODES operating_mode) +{ +#ifdef DEBUG_MODE + Serial.print("\n Writing to EEPROM: "); +#endif + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: +#ifdef DEBUG_MODE + Serial.print("ULP_MODE_SCREEN_OFF \n"); +#endif + for (uint16_t array_index = 0; array_index < BSEC_MAX_STATE_BLOB_SIZE; array_index++) + { + EEPROM.write(BSEC_EEPROM_ULP_REGION_START + array_index, bsec_state_ulp[array_index]); + +#ifdef DEBUG_MODE + Serial.print(EEPROM.read(BSEC_EEPROM_ULP_REGION_START + array_index)); + Serial.print(" "); + +#endif + } + EEPROM.write(BSEC_EEPROM_ULP_IDENTIFIER, BSEC_MAX_STATE_BLOB_SIZE); + break; + + case LP_MODE_SCREEN_ON: +#ifdef DEBUG_MODE + Serial.print("LP_MODE_SCREEN_ON \n"); +#endif + for (uint16_t array_index = 0; array_index < BSEC_MAX_STATE_BLOB_SIZE; array_index++) + { + EEPROM.write(BSEC_EEPROM_LP_REGION_START + array_index, bsec_state_lp[array_index]); + +#ifdef DEBUG_MODE + Serial.print(EEPROM.read(BSEC_EEPROM_LP_REGION_START + array_index)); + Serial.print(" "); +#endif + } + EEPROM.write(BSEC_EEPROM_LP_IDENTIFIER, BSEC_MAX_STATE_BLOB_SIZE); + + break; + + case CONT_MODE_BREATH: +#ifdef DEBUG_MODE + Serial.print("CONT_MODE_BREATH \n"); +#endif + for (uint16_t array_index = 0; array_index < EEPROM_BYTES_PER_REGION; array_index++) + { + EEPROM.write(BSEC_EEPROM_CONT_REGION_START + array_index, bsec_state_cont[array_index]); + +#ifdef DEBUG_MODE + Serial.print(EEPROM.read(BSEC_EEPROM_CONT_REGION_START + array_index)); + Serial.print(" "); +#endif + } + EEPROM.write(BSEC_EEPROM_CONT_IDENTIFIER, BSEC_MAX_STATE_BLOB_SIZE); + break; + + default: + break; + } + EEPROM.commit(); +} + +/** + * @brief Load the EEPROM values into appropriate RAM containers based on + * operating_mode + * @param operating_mode Defines the start EEPROM address for reading from EEPROM + * -ULP_MODE_SCREEN_OFF + * -LP_MODE_SCREEN_ON + * -CONT_MODE_BREATH + */ +void load_state(OPERATING_MODES operating_mode) +{ +#ifdef DEBUG_MODE + Serial.print("\n Loading from EEPROM: "); +#endif + switch (operating_mode) + { + case ULP_MODE_SCREEN_OFF: +#ifdef DEBUG_MODE + Serial.print("ULP_MODE_SCREEN_OFF \n"); +#endif + for (uint16_t array_index = 0; array_index < EEPROM_BYTES_PER_REGION; array_index++) + { + bsec_state_ulp[array_index] = EEPROM.read(BSEC_EEPROM_ULP_REGION_START + array_index); + +#ifdef DEBUG_MODE + Serial.print(bsec_state_ulp[array_index]); + Serial.print(" "); +#endif + } + break; + + case LP_MODE_SCREEN_ON: +#ifdef DEBUG_MODE + Serial.print("LP_MODE_SCREEN_ON \n"); +#endif + for (uint16_t array_index = 0; array_index < EEPROM_BYTES_PER_REGION; array_index++) + { + bsec_state_lp[array_index] = EEPROM.read(BSEC_EEPROM_LP_REGION_START + array_index); + +#ifdef DEBUG_MODE + Serial.print(bsec_state_lp[array_index]); + Serial.print(" "); +#endif + } + break; + + case CONT_MODE_BREATH: +#ifdef DEBUG_MODE + Serial.print("CONT_MODE_BREATH \n"); +#endif + for (uint16_t array_index = 0; array_index < EEPROM_BYTES_PER_REGION; array_index++) + { + bsec_state_cont[array_index] = EEPROM.read(BSEC_EEPROM_CONT_REGION_START + array_index); + +#ifdef DEBUG_MODE + Serial.print(bsec_state_cont[array_index]); + Serial.print(" "); +#endif + } + break; + + default: + break; + } +} + +/** + * @brief Report the current status of bme680 and bsec library. + */ +void report_status(void) +{ + /* Report Sensor status on serial terminal */ + if (iaqSensor.bsecStatus != BSEC_OK) { + if (iaqSensor.bsecStatus < BSEC_OK) { + output = "\nBSEC error code : " + String(iaqSensor.bsecStatus); + Serial.println(output); + for (;;) + err_leds(); /* Halt in case of failure */ + } else { + output = "\nBSEC warning code : " + String(iaqSensor.bsecStatus); + Serial.println(output); + } + } + + if (iaqSensor.bme68xStatus != BME68X_OK) { + if (iaqSensor.bme68xStatus < BME68X_OK) { + output = "\nBME68X error code : " + String(iaqSensor.bme68xStatus); + Serial.println(output); + for (;;) + err_leds(); /* Halt in case of failure */ + } else { + output = "\nBME68X warning code : " + String(iaqSensor.bme68xStatus); + Serial.println(output); + } + } +} + +void err_leds(void) +{ + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); +} diff --git a/keywords.txt b/keywords.txt index 46bdd67..e77e252 100644 --- a/keywords.txt +++ b/keywords.txt @@ -3,6 +3,7 @@ ####################################### Bsec KEYWORD1 +bsec_physical_sensor_t KEYWORD1 bsec_virtual_sensor_t KEYWORD1 bsec_library_return_t KEYWORD1 @@ -18,6 +19,7 @@ setState KEYWORD2 setConfig KEYWORD2 setTemperatureOffset KEYWORD2 getTimeMs KEYWORD2 +setTPH KEYWORD2 ####################################### # Instances(KEYWORD2) @@ -30,7 +32,7 @@ getTimeMs KEYWORD2 version KEYWORD2 nextCall KEYWORD2 bme680Status KEYWORD2 -status KEYWORD2 +bsecStatus KEYWORD2 iaq KEYWORD2 rawTemperature KEYWORD2 pressure KEYWORD2 @@ -50,8 +52,10 @@ staticIaqAccuracy KEYWORD2 co2Accuracy KEYWORD2 breathVocAccuracy KEYWORD2 compGasAccuracy KEYWORD2 -gasPercentageAcccuracy KEYWORD2 +gasPercentageAccuracy KEYWORD2 outputTimestamp KEYWORD2 +conf KEYWORD2 +heatrConf KEYWORD2 major KEYWORD2 minor KEYWORD2 major_bugfix KEYWORD2 @@ -67,10 +71,9 @@ BSEC_MAX_PROPERTY_BLOB_SIZE LITERAL1 BSEC_MAX_STATE_BLOB_SIZE LITERAL1 BSEC_SAMPLE_RATE_DISABLED LITERAL1 BSEC_SAMPLE_RATE_ULP LITERAL1 -BSEC_SAMPLE_RATE_CONTINUOUS LITERAL1 +BSEC_SAMPLE_RATE_CONT LITERAL1 BSEC_SAMPLE_RATE_LP LITERAL1 BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND LITERAL1 - BSEC_PROCESS_PRESSURE LITERAL1 BSEC_PROCESS_TEMPERATURE LITERAL1 BSEC_PROCESS_HUMIDITY LITERAL1 @@ -99,17 +102,16 @@ BSEC_OUTPUT_STABILIZATION_STATUS LITERAL1 BSEC_OUTPUT_RUN_IN_STATUS LITERAL1 BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE LITERAL1 BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY LITERAL1 -BSEC_OUTPUT_COMPENSATED_GAS LITERAL1 BSEC_OUTPUT_GAS_PERCENTAGE LITERAL1 # BSEC return codes BSEC_OK LITERAL1 BSEC_E_DOSTEPS_INVALIDINPUT LITERAL1 BSEC_E_DOSTEPS_VALUELIMITS LITERAL1 +BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE LITERAL1 BSEC_E_DOSTEPS_DUPLICATEINPUT LITERAL1 BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE LITERAL1 BSEC_W_DOSTEPS_EXCESSOUTPUTS LITERAL1 -BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE LITERAL1 BSEC_E_SU_WRONGDATARATE LITERAL1 BSEC_E_SU_SAMPLERATELIMITS LITERAL1 BSEC_E_SU_DUPLICATEGATE LITERAL1 @@ -135,19 +137,19 @@ BSEC_E_SET_INVALIDLENGTH LITERAL1 BSEC_W_SC_CALL_TIMING_VIOLATION LITERAL1 BSEC_W_SC_MODEXCEEDULPTIMELIMIT LITERAL1 BSEC_W_SC_MODINSUFFICIENTWAITTIME LITERAL1 - -# BME680 constants -BME680_FLOAT_POINT_COMPENSATION -BME680_I2C_ADDR_PRIMARY LITERAL1 -BME680_I2C_ADDR_SECONDARY LITERAL1 -BME680_CHIP_ID LITERAL1 -BME680_OK LITERAL1 -BME680_E_NULL_PTR LITERAL1 -BME680_E_COM_FAIL LITERAL1 -BME680_E_DEV_NOT_FOUND LITERAL1 -BME680_E_INVALID_LENGTH LITERAL1 -BME680_W_DEFINE_PWR_MODE LITERAL1 -BME680_W_NO_NEW_DATA LITERAL1 -BME680_SPI_INTF LITERAL1 -BME680_I2C_INTF LITERAL1 + +# BME68X constants +BME68X_CHIP_ID LITERAL1 +BME68X_I2C_ADDR_LOW LITERAL1 +BME68X_I2C_ADDR_HIGH LITERAL1 +BME68X_SOFT_RESET_CMD LITERAL1 +BME68X_OK LITERAL1 +BME68X_E_NULL_PTR LITERAL1 +BME68X_E_COM_FAIL LITERAL1 +BME68X_E_DEV_NOT_FOUND LITERAL1 +BME68X_E_INVALID_LENGTH LITERAL1 +BME68X_W_DEFINE_OP_MODE LITERAL1 +BME68X_W_NO_NEW_DATA LITERAL1 +BME68X_SPI_INTF LITERAL1 +BME68X_I2C_INTF LITERAL1 diff --git a/library.json b/library.json index 395aa75..a8fb3f6 100644 --- a/library.json +++ b/library.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/BoschSensortec/BSEC-Arduino-library" }, - "version": "1.6.1480", + "version": "v1.8.1492", "authors": { "name": "Bosch Sensortec", "email": "contact@bosch-sensortec.com" @@ -28,20 +28,20 @@ "base": "examples/basic_config_state", "files": ["basic_config_state.ino"] }, - { - "name": "Basic usage with config state saves and multiple sensors", - "base": "examples/basic_config_state_multi", - "files": ["basic_config_state_multi.ino"] - }, + { + "name": "Basic usage with config state saves and triggered ULP plus and LP measurements for different set of parameters", + "base": "examples/basic_config_state_ULP_LP", + "files": ["basic_config_state_ULP_LP.ino"] + }, { "name": "Basic usage with config state saves and triggered ULP plus measurements", "base": "examples/basic_config_state_ulp_plus", "files": ["basic_config_state_ulp_plus.ino"] }, { - "name": "ESP32 deep sleep", - "base": "examples/esp32DeepSleep", - "files": ["esp32DeepSleep.ino"] + "name": "Octopus Demo", + "base": "examples/octopus_demo", + "files": ["octopus_demo.ino"] } ] } diff --git a/library.properties b/library.properties index e195c69..cc79f3f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=BSEC Software Library -version=1.6.1480 +version=1.8.1492 author=Bosch Sensortec maintainer=Bosch Sensortec sentence=Bosch Sensortec Environmental Cluster (BSEC) Software library diff --git a/src/atmega2560/libalgobsec.a b/src/atmega2560/libalgobsec.a index b46f227..146f7cd 100644 Binary files a/src/atmega2560/libalgobsec.a and b/src/atmega2560/libalgobsec.a differ diff --git a/src/bme680/README.md b/src/bme680/README.md deleted file mode 100644 index f297b65..0000000 --- a/src/bme680/README.md +++ /dev/null @@ -1,282 +0,0 @@ -# BME680 sensor API - -## Introduction - -This package contains the Bosch Sensortec's BME680 gas sensor API - -The sensor driver package includes bme680.h, bme680.c and bme680_defs.h files - -## Version - -File | Version | Date ---------------|---------|------------- -bme680.c | 3.5.10 | 23 Jan 2020 -bme680.h | 3.5.10 | 23 Jan 2020 -bme680_defs.h | 3.5.10 | 23 Jan 2020 - -## Integration details - -* Integrate bme680.h, bme680_defs.h and bme680.c file in to your project. -* Include the bme680.h file in your code like below. - -``` c -#include "bme680.h" -``` - -## File information - -* bme680_defs.h : This header file has the constants, macros and datatype declarations. -* bme680.h : This header file contains the declarations of the sensor driver APIs. -* bme680.c : This source file contains the definitions of the sensor driver APIs. - -## Supported sensor interfaces - -* SPI 4-wire -* I2C - -## Usage guide - -### Initializing the sensor - -To initialize the sensor, you will first need to create a device structure. You -can do this by creating an instance of the structure bme680_dev. Then go on to -fill in the various parameters as shown below - -#### Example for SPI 4-Wire - -``` c - struct bme680_dev gas_sensor; - - /* You may assign a chip select identifier to be handled later */ - gas_sensor.dev_id = 0; - gas_sensor.intf = BME680_SPI_INTF; - gas_sensor.read = user_spi_read; - gas_sensor.write = user_spi_write; - gas_sensor.delay_ms = user_delay_ms; - /* amb_temp can be set to 25 prior to configuring the gas sensor - * or by performing a few temperature readings without operating the gas sensor. - */ - gas_sensor.amb_temp = 25; - - int8_t rslt = BME680_OK; - rslt = bme680_init(&gas_sensor); -``` - -#### Example for I2C - -``` c - struct bme680_dev gas_sensor; - - gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY; - gas_sensor.intf = BME680_I2C_INTF; - gas_sensor.read = user_i2c_read; - gas_sensor.write = user_i2c_write; - gas_sensor.delay_ms = user_delay_ms; - /* amb_temp can be set to 25 prior to configuring the gas sensor - * or by performing a few temperature readings without operating the gas sensor. - */ - gas_sensor.amb_temp = 25; - - - int8_t rslt = BME680_OK; - rslt = bme680_init(&gas_sensor); -``` - -Regarding compensation functions for temperature, pressure, humidity and gas we have two implementations. - - - Integer version - - floating point version - -By default, Integer version is used in the API - -If the user needs the floating point version, the user has to un-comment BME680_FLOAT_POINT_COMPENSATION macro -in bme680_defs.h file or to add it in the compiler flags. - -### Configuring the sensor - -#### Example for configuring the sensor in forced mode - -``` c - uint8_t set_required_settings; - - /* Set the temperature, pressure and humidity settings */ - gas_sensor.tph_sett.os_hum = BME680_OS_2X; - gas_sensor.tph_sett.os_pres = BME680_OS_4X; - gas_sensor.tph_sett.os_temp = BME680_OS_8X; - gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3; - - /* Set the remaining gas sensor settings and link the heating profile */ - gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS; - /* Create a ramp heat waveform in 3 steps */ - gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */ - gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */ - - /* Select the power mode */ - /* Must be set before writing the sensor configuration */ - gas_sensor.power_mode = BME680_FORCED_MODE; - - /* Set the required sensor settings needed */ - set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL - | BME680_GAS_SENSOR_SEL; - - /* Set the desired sensor configuration */ - rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor); - - /* Set the power mode */ - rslt = bme680_set_sensor_mode(&gas_sensor); - - -``` - -### Reading sensor data - -#### Example for reading all sensor data - -``` c - /* Get the total measurement duration so as to sleep or wait till the - * measurement is complete */ - uint16_t meas_period; - bme680_get_profile_dur(&meas_period, &gas_sensor); - - struct bme680_field_data data; - - while(1) - { - user_delay_ms(meas_period); /* Delay till the measurement is ready */ - - rslt = bme680_get_sensor_data(&data, &gas_sensor); - - printf("T: %.2f degC, P: %.2f hPa, H %.2f %%rH ", data.temperature / 100.0f, - data.pressure / 100.0f, data.humidity / 1000.0f ); - /* Avoid using measurements from an unstable heating setup */ - if(data.status & BME680_GASM_VALID_MSK) - printf(", G: %d ohms", data.gas_resistance); - - printf("\r\n"); - - /* Trigger the next measurement if you would like to read data out continuously */ - if (gas_sensor.power_mode == BME680_FORCED_MODE) { - rslt = bme680_set_sensor_mode(&gas_sensor); - } - } -``` - -### Templates for function pointers - -``` c - -void user_delay_ms(uint32_t period) -{ - /* - * Return control or wait, - * for a period amount of milliseconds - */ -} - -int8_t user_spi_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) -{ - int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */ - - /* - * The parameter dev_id can be used as a variable to select which Chip Select pin has - * to be set low to activate the relevant device on the SPI bus - */ - - /* - * Data on the bus should be like - * |----------------+---------------------+-------------| - * | MOSI | MISO | Chip Select | - * |----------------+---------------------|-------------| - * | (don't care) | (don't care) | HIGH | - * | (reg_addr) | (don't care) | LOW | - * | (don't care) | (reg_data[0]) | LOW | - * | (....) | (....) | LOW | - * | (don't care) | (reg_data[len - 1]) | LOW | - * | (don't care) | (don't care) | HIGH | - * |----------------+---------------------|-------------| - */ - - return rslt; -} - -int8_t user_spi_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) -{ - int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */ - - /* - * The parameter dev_id can be used as a variable to select which Chip Select pin has - * to be set low to activate the relevant device on the SPI bus - */ - - /* - * Data on the bus should be like - * |---------------------+--------------+-------------| - * | MOSI | MISO | Chip Select | - * |---------------------+--------------|-------------| - * | (don't care) | (don't care) | HIGH | - * | (reg_addr) | (don't care) | LOW | - * | (reg_data[0]) | (don't care) | LOW | - * | (....) | (....) | LOW | - * | (reg_data[len - 1]) | (don't care) | LOW | - * | (don't care) | (don't care) | HIGH | - * |---------------------+--------------|-------------| - */ - - return rslt; -} - -int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) -{ - int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */ - - /* - * The parameter dev_id can be used as a variable to store the I2C address of the device - */ - - /* - * Data on the bus should be like - * |------------+---------------------| - * | I2C action | Data | - * |------------+---------------------| - * | Start | - | - * | Write | (reg_addr) | - * | Stop | - | - * | Start | - | - * | Read | (reg_data[0]) | - * | Read | (....) | - * | Read | (reg_data[len - 1]) | - * | Stop | - | - * |------------+---------------------| - */ - - return rslt; -} - -int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len) -{ - int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */ - - /* - * The parameter dev_id can be used as a variable to store the I2C address of the device - */ - - /* - * Data on the bus should be like - * |------------+---------------------| - * | I2C action | Data | - * |------------+---------------------| - * | Start | - | - * | Write | (reg_addr) | - * | Write | (reg_data[0]) | - * | Write | (....) | - * | Write | (reg_data[len - 1]) | - * | Stop | - | - * |------------+---------------------| - */ - - return rslt; -} - -``` - -## Copyright (C) 2020 Bosch Sensortec GmbH. All rights reserved. \ No newline at end of file diff --git a/src/bme680/bme680.c b/src/bme680/bme680.c deleted file mode 100644 index 5b138c0..0000000 --- a/src/bme680/bme680.c +++ /dev/null @@ -1,1358 +0,0 @@ -/**\mainpage - * Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. - * - * BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * File bme680.c - * @date 23 Jan 2020 - * @version 3.5.10 - * - */ - -/*! @file bme680.c - @brief Sensor driver for BME680 sensor */ -#include "bme680.h" - -/*! - * @brief This internal API is used to read the calibrated data from the sensor. - * - * This function is used to retrieve the calibration - * data from the image registers of the sensor. - * - * @note Registers 89h to A1h for calibration data 1 to 24 - * from bit 0 to 7 - * @note Registers E1h to F0h for calibration data 25 to 40 - * from bit 0 to 7 - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status. - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t get_calib_data(struct bme680_dev *dev); - -/*! - * @brief This internal API is used to set the gas configuration of the sensor. - * - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status. - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t set_gas_config(struct bme680_dev *dev); - -/*! - * @brief This internal API is used to get the gas configuration of the sensor. - * @note heatr_temp and heatr_dur values are currently register data - * and not the actual values set - * - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status. - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t get_gas_config(struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the Heat duration value. - * - * @param[in] dur :Value of the duration to be shared. - * - * @return uint8_t threshold duration after calculation. - */ -static uint8_t calc_heater_dur(uint16_t dur); - -#ifndef BME680_FLOAT_POINT_COMPENSATION - -/*! - * @brief This internal API is used to calculate the temperature value. - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] temp_adc :Contains the temperature ADC value . - * - * @return uint32_t calculated temperature. - */ -static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the pressure value. - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] pres_adc :Contains the pressure ADC value . - * - * @return uint32_t calculated pressure. - */ -static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the humidity value. - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] hum_adc :Contains the humidity ADC value. - * - * @return uint32_t calculated humidity. - */ -static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the Gas Resistance value. - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] gas_res_adc :Contains the Gas Resistance ADC value. - * @param[in] gas_range :Contains the range of gas values. - * - * @return uint32_t calculated gas resistance. - */ -static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the Heat Resistance value. - * - * @param[in] dev : Structure instance of bme680_dev - * @param[in] temp : Contains the target temperature value. - * - * @return uint8_t calculated heater resistance. - */ -static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev); - -#else -/*! - * @brief This internal API is used to calculate the - * temperature value value in float format - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] temp_adc :Contains the temperature ADC value . - * - * @return Calculated temperature in float - */ -static float calc_temperature(uint32_t temp_adc, struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the - * pressure value value in float format - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] pres_adc :Contains the pressure ADC value . - * - * @return Calculated pressure in float. - */ -static float calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the - * humidity value value in float format - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] hum_adc :Contains the humidity ADC value. - * - * @return Calculated humidity in float. - */ -static float calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the - * gas resistance value value in float format - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] gas_res_adc :Contains the Gas Resistance ADC value. - * @param[in] gas_range :Contains the range of gas values. - * - * @return Calculated gas resistance in float. - */ -static float calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to calculate the - * heater resistance value in float format - * - * @param[in] temp : Contains the target temperature value. - * @param[in] dev : Structure instance of bme680_dev. - * - * @return Calculated heater resistance in float. - */ -static float calc_heater_res(uint16_t temp, const struct bme680_dev *dev); - -#endif - -/*! - * @brief This internal API is used to calculate the field data of sensor. - * - * @param[out] data :Structure instance to hold the data - * @param[in] dev :Structure instance of bme680_dev. - * - * @return int8_t result of the field data from sensor. - */ -static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev); - -/*! - * @brief This internal API is used to set the memory page - * based on register address. - * - * The value of memory page - * value | Description - * --------|-------------- - * 0 | BME680_PAGE0_SPI - * 1 | BME680_PAGE1_SPI - * - * @param[in] dev :Structure instance of bme680_dev. - * @param[in] reg_addr :Contains the register address array. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev); - -/*! - * @brief This internal API is used to get the memory page based - * on register address. - * - * The value of memory page - * value | Description - * --------|-------------- - * 0 | BME680_PAGE0_SPI - * 1 | BME680_PAGE1_SPI - * - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t get_mem_page(struct bme680_dev *dev); - -/*! - * @brief This internal API is used to validate the device pointer for - * null conditions. - * - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t null_ptr_check(const struct bme680_dev *dev); - -/*! - * @brief This internal API is used to check the boundary - * conditions. - * - * @param[in] value :pointer to the value. - * @param[in] min :minimum value. - * @param[in] max :maximum value. - * @param[in] dev :Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev); - -/****************** Global Function Definitions *******************************/ -/*! - *@brief This API is the entry point. - *It reads the chip-id and calibration data from the sensor. - */ -int8_t bme680_init(struct bme680_dev *dev) -{ - int8_t rslt; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - /* Soft reset to restore it to default values*/ - rslt = bme680_soft_reset(dev); - if (rslt == BME680_OK) { - rslt = bme680_get_regs(BME680_CHIP_ID_ADDR, &dev->chip_id, 1, dev); - if (rslt == BME680_OK) { - if (dev->chip_id == BME680_CHIP_ID) { - /* Get the Calibration data */ - rslt = get_calib_data(dev); - } else { - rslt = BME680_E_DEV_NOT_FOUND; - } - } - } - } - - return rslt; -} - -/*! - * @brief This API reads the data from the given register address of the sensor. - */ -int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev) -{ - int8_t rslt; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if (dev->intf == BME680_SPI_INTF) { - /* Set the memory page */ - rslt = set_mem_page(reg_addr, dev); - if (rslt == BME680_OK) - reg_addr = reg_addr | BME680_SPI_RD_MSK; - } - dev->com_rslt = dev->read(dev->dev_id, reg_addr, reg_data, len); - if (dev->com_rslt != 0) - rslt = BME680_E_COM_FAIL; - } - - return rslt; -} - -/*! - * @brief This API writes the given data to the register address - * of the sensor. - */ -int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev) -{ - int8_t rslt; - /* Length of the temporary buffer is 2*(length of register)*/ - uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = { 0 }; - uint16_t index; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if ((len > 0) && (len < BME680_TMP_BUFFER_LENGTH / 2)) { - /* Interleave the 2 arrays */ - for (index = 0; index < len; index++) { - if (dev->intf == BME680_SPI_INTF) { - /* Set the memory page */ - rslt = set_mem_page(reg_addr[index], dev); - tmp_buff[(2 * index)] = reg_addr[index] & BME680_SPI_WR_MSK; - } else { - tmp_buff[(2 * index)] = reg_addr[index]; - } - tmp_buff[(2 * index) + 1] = reg_data[index]; - } - /* Write the interleaved array */ - if (rslt == BME680_OK) { - dev->com_rslt = dev->write(dev->dev_id, tmp_buff[0], &tmp_buff[1], (2 * len) - 1); - if (dev->com_rslt != 0) - rslt = BME680_E_COM_FAIL; - } - } else { - rslt = BME680_E_INVALID_LENGTH; - } - } - - return rslt; -} - -/*! - * @brief This API performs the soft reset of the sensor. - */ -int8_t bme680_soft_reset(struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t reg_addr = BME680_SOFT_RESET_ADDR; - /* 0xb6 is the soft reset command */ - uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if (dev->intf == BME680_SPI_INTF) - rslt = get_mem_page(dev); - - /* Reset the device */ - if (rslt == BME680_OK) { - rslt = bme680_set_regs(®_addr, &soft_rst_cmd, 1, dev); - /* Wait for 5ms */ - dev->delay_ms(BME680_RESET_PERIOD); - - if (rslt == BME680_OK) { - /* After reset get the memory page */ - if (dev->intf == BME680_SPI_INTF) - rslt = get_mem_page(dev); - } - } - } - - return rslt; -} - -/*! - * @brief This API is used to set the oversampling, filter and T,P,H, gas selection - * settings in the sensor. - */ -int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t reg_addr; - uint8_t data = 0; - uint8_t count = 0; - uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = { 0 }; - uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; - uint8_t intended_power_mode = dev->power_mode; /* Save intended power mode */ - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if (desired_settings & BME680_GAS_MEAS_SEL) - rslt = set_gas_config(dev); - - dev->power_mode = BME680_SLEEP_MODE; - if (rslt == BME680_OK) - rslt = bme680_set_sensor_mode(dev); - - /* Selecting the filter */ - if (desired_settings & BME680_FILTER_SEL) { - rslt = boundary_check(&dev->tph_sett.filter, BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127, dev); - reg_addr = BME680_CONF_ODR_FILT_ADDR; - - if (rslt == BME680_OK) - rslt = bme680_get_regs(reg_addr, &data, 1, dev); - - if (desired_settings & BME680_FILTER_SEL) - data = BME680_SET_BITS(data, BME680_FILTER, dev->tph_sett.filter); - - reg_array[count] = reg_addr; /* Append configuration */ - data_array[count] = data; - count++; - } - - /* Selecting heater control for the sensor */ - if (desired_settings & BME680_HCNTRL_SEL) { - rslt = boundary_check(&dev->gas_sett.heatr_ctrl, BME680_ENABLE_HEATER, - BME680_DISABLE_HEATER, dev); - reg_addr = BME680_CONF_HEAT_CTRL_ADDR; - - if (rslt == BME680_OK) - rslt = bme680_get_regs(reg_addr, &data, 1, dev); - data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, dev->gas_sett.heatr_ctrl); - - reg_array[count] = reg_addr; /* Append configuration */ - data_array[count] = data; - count++; - } - - /* Selecting heater T,P oversampling for the sensor */ - if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { - rslt = boundary_check(&dev->tph_sett.os_temp, BME680_OS_NONE, BME680_OS_16X, dev); - reg_addr = BME680_CONF_T_P_MODE_ADDR; - - if (rslt == BME680_OK) - rslt = bme680_get_regs(reg_addr, &data, 1, dev); - - if (desired_settings & BME680_OST_SEL) - data = BME680_SET_BITS(data, BME680_OST, dev->tph_sett.os_temp); - - if (desired_settings & BME680_OSP_SEL) - data = BME680_SET_BITS(data, BME680_OSP, dev->tph_sett.os_pres); - - reg_array[count] = reg_addr; - data_array[count] = data; - count++; - } - - /* Selecting humidity oversampling for the sensor */ - if (desired_settings & BME680_OSH_SEL) { - rslt = boundary_check(&dev->tph_sett.os_hum, BME680_OS_NONE, BME680_OS_16X, dev); - reg_addr = BME680_CONF_OS_H_ADDR; - - if (rslt == BME680_OK) - rslt = bme680_get_regs(reg_addr, &data, 1, dev); - data = BME680_SET_BITS_POS_0(data, BME680_OSH, dev->tph_sett.os_hum); - - reg_array[count] = reg_addr; /* Append configuration */ - data_array[count] = data; - count++; - } - - /* Selecting the runGas and NB conversion settings for the sensor */ - if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { - rslt = boundary_check(&dev->gas_sett.run_gas, BME680_RUN_GAS_DISABLE, - BME680_RUN_GAS_ENABLE, dev); - if (rslt == BME680_OK) { - /* Validate boundary conditions */ - rslt = boundary_check(&dev->gas_sett.nb_conv, BME680_NBCONV_MIN, - BME680_NBCONV_MAX, dev); - } - - reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR; - - if (rslt == BME680_OK) - rslt = bme680_get_regs(reg_addr, &data, 1, dev); - - if (desired_settings & BME680_RUN_GAS_SEL) - data = BME680_SET_BITS(data, BME680_RUN_GAS, dev->gas_sett.run_gas); - - if (desired_settings & BME680_NBCONV_SEL) - data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, dev->gas_sett.nb_conv); - - reg_array[count] = reg_addr; /* Append configuration */ - data_array[count] = data; - count++; - } - - if (rslt == BME680_OK) - rslt = bme680_set_regs(reg_array, data_array, count, dev); - - /* Restore previous intended power mode */ - dev->power_mode = intended_power_mode; - } - - return rslt; -} - -/*! - * @brief This API is used to get the oversampling, filter and T,P,H, gas selection - * settings in the sensor. - */ -int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) -{ - int8_t rslt; - /* starting address of the register array for burst read*/ - uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR; - uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - rslt = bme680_get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH, dev); - - if (rslt == BME680_OK) { - if (desired_settings & BME680_GAS_MEAS_SEL) - rslt = get_gas_config(dev); - - /* get the T,P,H ,Filter,ODR settings here */ - if (desired_settings & BME680_FILTER_SEL) - dev->tph_sett.filter = BME680_GET_BITS(data_array[BME680_REG_FILTER_INDEX], - BME680_FILTER); - - if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { - dev->tph_sett.os_temp = BME680_GET_BITS(data_array[BME680_REG_TEMP_INDEX], BME680_OST); - dev->tph_sett.os_pres = BME680_GET_BITS(data_array[BME680_REG_PRES_INDEX], BME680_OSP); - } - - if (desired_settings & BME680_OSH_SEL) - dev->tph_sett.os_hum = BME680_GET_BITS_POS_0(data_array[BME680_REG_HUM_INDEX], - BME680_OSH); - - /* get the gas related settings */ - if (desired_settings & BME680_HCNTRL_SEL) - dev->gas_sett.heatr_ctrl = BME680_GET_BITS_POS_0(data_array[BME680_REG_HCTRL_INDEX], - BME680_HCTRL); - - if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { - dev->gas_sett.nb_conv = BME680_GET_BITS_POS_0(data_array[BME680_REG_NBCONV_INDEX], - BME680_NBCONV); - dev->gas_sett.run_gas = BME680_GET_BITS(data_array[BME680_REG_RUN_GAS_INDEX], - BME680_RUN_GAS); - } - } - } else { - rslt = BME680_E_NULL_PTR; - } - - return rslt; -} - -/*! - * @brief This API is used to set the power mode of the sensor. - */ -int8_t bme680_set_sensor_mode(struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t tmp_pow_mode; - uint8_t pow_mode = 0; - uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - /* Call repeatedly until in sleep */ - do { - rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1, dev); - if (rslt == BME680_OK) { - /* Put to sleep before changing mode */ - pow_mode = (tmp_pow_mode & BME680_MODE_MSK); - - if (pow_mode != BME680_SLEEP_MODE) { - tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */ - rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); - dev->delay_ms(BME680_POLL_PERIOD_MS); - } - } - } while (pow_mode != BME680_SLEEP_MODE); - - /* Already in sleep */ - if (dev->power_mode != BME680_SLEEP_MODE) { - tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (dev->power_mode & BME680_MODE_MSK); - if (rslt == BME680_OK) - rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); - } - } - - return rslt; -} - -/*! - * @brief This API is used to get the power mode of the sensor. - */ -int8_t bme680_get_sensor_mode(struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t mode; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1, dev); - /* Masking the other register bit info*/ - dev->power_mode = mode & BME680_MODE_MSK; - } - - return rslt; -} - -/*! - * @brief This API is used to set the profile duration of the sensor. - */ -void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev) -{ - uint32_t tph_dur; /* Calculate in us */ - uint32_t meas_cycles; - uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16}; - - meas_cycles = os_to_meas_cycles[dev->tph_sett.os_temp]; - meas_cycles += os_to_meas_cycles[dev->tph_sett.os_pres]; - meas_cycles += os_to_meas_cycles[dev->tph_sett.os_hum]; - - /* TPH measurement duration */ - tph_dur = meas_cycles * UINT32_C(1963); - tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ - tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ - tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ - tph_dur /= UINT32_C(1000); /* Convert to ms */ - - tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ - /* The remaining time should be used for heating */ - dev->gas_sett.heatr_dur = duration - (uint16_t) tph_dur; -} - -/*! - * @brief This API is used to get the profile duration of the sensor. - */ -void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev) -{ - uint32_t tph_dur; /* Calculate in us */ - uint32_t meas_cycles; - uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16}; - - meas_cycles = os_to_meas_cycles[dev->tph_sett.os_temp]; - meas_cycles += os_to_meas_cycles[dev->tph_sett.os_pres]; - meas_cycles += os_to_meas_cycles[dev->tph_sett.os_hum]; - - /* TPH measurement duration */ - tph_dur = meas_cycles * UINT32_C(1963); - tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ - tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ - tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ - tph_dur /= UINT32_C(1000); /* Convert to ms */ - - tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ - - *duration = (uint16_t) tph_dur; - - /* Get the gas duration only when the run gas is enabled */ - if (dev->gas_sett.run_gas) { - /* The remaining time should be used for heating */ - *duration += dev->gas_sett.heatr_dur; - } -} - -/*! - * @brief This API reads the pressure, temperature and humidity and gas data - * from the sensor, compensates the data and store it in the bme680_data - * structure instance passed by the user. - */ -int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev) -{ - int8_t rslt; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - /* Reading the sensor data in forced mode only */ - rslt = read_field_data(data, dev); - if (rslt == BME680_OK) { - if (data->status & BME680_NEW_DATA_MSK) - dev->new_fields = 1; - else - dev->new_fields = 0; - } - } - - return rslt; -} - -/*! - * @brief This internal API is used to read the calibrated data from the sensor. - */ -static int8_t get_calib_data(struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t coeff_array[BME680_COEFF_SIZE] = { 0 }; - uint8_t temp_var = 0; /* Temporary variable */ - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - rslt = bme680_get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN, dev); - /* Append the second half in the same array */ - if (rslt == BME680_OK) - rslt = bme680_get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN] - , BME680_COEFF_ADDR2_LEN, dev); - - /* Temperature related coefficients */ - dev->calib.par_t1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T1_MSB_REG], - coeff_array[BME680_T1_LSB_REG])); - dev->calib.par_t2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T2_MSB_REG], - coeff_array[BME680_T2_LSB_REG])); - dev->calib.par_t3 = (int8_t) (coeff_array[BME680_T3_REG]); - - /* Pressure related coefficients */ - dev->calib.par_p1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P1_MSB_REG], - coeff_array[BME680_P1_LSB_REG])); - dev->calib.par_p2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P2_MSB_REG], - coeff_array[BME680_P2_LSB_REG])); - dev->calib.par_p3 = (int8_t) coeff_array[BME680_P3_REG]; - dev->calib.par_p4 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P4_MSB_REG], - coeff_array[BME680_P4_LSB_REG])); - dev->calib.par_p5 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P5_MSB_REG], - coeff_array[BME680_P5_LSB_REG])); - dev->calib.par_p6 = (int8_t) (coeff_array[BME680_P6_REG]); - dev->calib.par_p7 = (int8_t) (coeff_array[BME680_P7_REG]); - dev->calib.par_p8 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P8_MSB_REG], - coeff_array[BME680_P8_LSB_REG])); - dev->calib.par_p9 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P9_MSB_REG], - coeff_array[BME680_P9_LSB_REG])); - dev->calib.par_p10 = (uint8_t) (coeff_array[BME680_P10_REG]); - - /* Humidity related coefficients */ - dev->calib.par_h1 = (uint16_t) (((uint16_t) coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) - | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); - dev->calib.par_h2 = (uint16_t) (((uint16_t) coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) - | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); - dev->calib.par_h3 = (int8_t) coeff_array[BME680_H3_REG]; - dev->calib.par_h4 = (int8_t) coeff_array[BME680_H4_REG]; - dev->calib.par_h5 = (int8_t) coeff_array[BME680_H5_REG]; - dev->calib.par_h6 = (uint8_t) coeff_array[BME680_H6_REG]; - dev->calib.par_h7 = (int8_t) coeff_array[BME680_H7_REG]; - - /* Gas heater related coefficients */ - dev->calib.par_gh1 = (int8_t) coeff_array[BME680_GH1_REG]; - dev->calib.par_gh2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG], - coeff_array[BME680_GH2_LSB_REG])); - dev->calib.par_gh3 = (int8_t) coeff_array[BME680_GH3_REG]; - - /* Other coefficients */ - if (rslt == BME680_OK) { - rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1, dev); - - dev->calib.res_heat_range = ((temp_var & BME680_RHRANGE_MSK) / 16); - if (rslt == BME680_OK) { - rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1, dev); - - dev->calib.res_heat_val = (int8_t) temp_var; - if (rslt == BME680_OK) - rslt = bme680_get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1, dev); - } - } - dev->calib.range_sw_err = ((int8_t) temp_var & (int8_t) BME680_RSERROR_MSK) / 16; - } - - return rslt; -} - -/*! - * @brief This internal API is used to set the gas configuration of the sensor. - */ -static int8_t set_gas_config(struct bme680_dev *dev) -{ - int8_t rslt; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - - uint8_t reg_addr[2] = {0}; - uint8_t reg_data[2] = {0}; - - if (dev->power_mode == BME680_FORCED_MODE) { - reg_addr[0] = BME680_RES_HEAT0_ADDR; - reg_data[0] = calc_heater_res(dev->gas_sett.heatr_temp, dev); - reg_addr[1] = BME680_GAS_WAIT0_ADDR; - reg_data[1] = calc_heater_dur(dev->gas_sett.heatr_dur); - dev->gas_sett.nb_conv = 0; - } else { - rslt = BME680_W_DEFINE_PWR_MODE; - } - if (rslt == BME680_OK) - rslt = bme680_set_regs(reg_addr, reg_data, 2, dev); - } - - return rslt; -} - -/*! - * @brief This internal API is used to get the gas configuration of the sensor. - * @note heatr_temp and heatr_dur values are currently register data - * and not the actual values set - */ -static int8_t get_gas_config(struct bme680_dev *dev) -{ - int8_t rslt; - /* starting address of the register array for burst read*/ - uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START; - uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START; - uint8_t reg_data = 0; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if (BME680_SPI_INTF == dev->intf) { - /* Memory page switch the SPI address*/ - rslt = set_mem_page(reg_addr1, dev); - } - - if (rslt == BME680_OK) { - rslt = bme680_get_regs(reg_addr1, ®_data, 1, dev); - if (rslt == BME680_OK) { - dev->gas_sett.heatr_temp = reg_data; - rslt = bme680_get_regs(reg_addr2, ®_data, 1, dev); - if (rslt == BME680_OK) { - /* Heating duration register value */ - dev->gas_sett.heatr_dur = reg_data; - } - } - } - } - - return rslt; -} - -#ifndef BME680_FLOAT_POINT_COMPENSATION - -/*! - * @brief This internal API is used to calculate the temperature value. - */ -static int16_t calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) -{ - int64_t var1; - int64_t var2; - int64_t var3; - int16_t calc_temp; - - var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib.par_t1 << 1); - var2 = (var1 * (int32_t) dev->calib.par_t2) >> 11; - var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; - var3 = ((var3) * ((int32_t) dev->calib.par_t3 << 4)) >> 14; - dev->calib.t_fine = (int32_t) (var2 + var3); - calc_temp = (int16_t) (((dev->calib.t_fine * 5) + 128) >> 8); - - return calc_temp; -} - -/*! - * @brief This internal API is used to calculate the pressure value. - */ -static uint32_t calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) -{ - int32_t var1; - int32_t var2; - int32_t var3; - int32_t pressure_comp; - - var1 = (((int32_t)dev->calib.t_fine) >> 1) - 64000; - var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * - (int32_t)dev->calib.par_p6) >> 2; - var2 = var2 + ((var1 * (int32_t)dev->calib.par_p5) << 1); - var2 = (var2 >> 2) + ((int32_t)dev->calib.par_p4 << 16); - var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * - ((int32_t)dev->calib.par_p3 << 5)) >> 3) + - (((int32_t)dev->calib.par_p2 * var1) >> 1); - var1 = var1 >> 18; - var1 = ((32768 + var1) * (int32_t)dev->calib.par_p1) >> 15; - pressure_comp = 1048576 - pres_adc; - pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125)); - if (pressure_comp >= BME680_MAX_OVERFLOW_VAL) - pressure_comp = ((pressure_comp / var1) << 1); - else - pressure_comp = ((pressure_comp << 1) / var1); - var1 = ((int32_t)dev->calib.par_p9 * (int32_t)(((pressure_comp >> 3) * - (pressure_comp >> 3)) >> 13)) >> 12; - var2 = ((int32_t)(pressure_comp >> 2) * - (int32_t)dev->calib.par_p8) >> 13; - var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * - (int32_t)(pressure_comp >> 8) * - (int32_t)dev->calib.par_p10) >> 17; - - pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 + - ((int32_t)dev->calib.par_p7 << 7)) >> 4); - - return (uint32_t)pressure_comp; - -} - -/*! - * @brief This internal API is used to calculate the humidity value. - */ -static uint32_t calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) -{ - int32_t var1; - int32_t var2; - int32_t var3; - int32_t var4; - int32_t var5; - int32_t var6; - int32_t temp_scaled; - int32_t calc_hum; - - temp_scaled = (((int32_t) dev->calib.t_fine * 5) + 128) >> 8; - var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) dev->calib.par_h1 * 16))) - - (((temp_scaled * (int32_t) dev->calib.par_h3) / ((int32_t) 100)) >> 1); - var2 = ((int32_t) dev->calib.par_h2 - * (((temp_scaled * (int32_t) dev->calib.par_h4) / ((int32_t) 100)) - + (((temp_scaled * ((temp_scaled * (int32_t) dev->calib.par_h5) / ((int32_t) 100))) >> 6) - / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10; - var3 = var1 * var2; - var4 = (int32_t) dev->calib.par_h6 << 7; - var4 = ((var4) + ((temp_scaled * (int32_t) dev->calib.par_h7) / ((int32_t) 100))) >> 4; - var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; - var6 = (var4 * var5) >> 1; - calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12; - - if (calc_hum > 100000) /* Cap at 100%rH */ - calc_hum = 100000; - else if (calc_hum < 0) - calc_hum = 0; - - return (uint32_t) calc_hum; -} - -/*! - * @brief This internal API is used to calculate the Gas Resistance value. - */ -static uint32_t calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev) -{ - int64_t var1; - uint64_t var2; - int64_t var3; - uint32_t calc_gas_res; - /**Look up table 1 for the possible gas range values */ - uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), - UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), - UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), - UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) }; - /**Look up table 2 for the possible gas range values */ - uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), - UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), - UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), - UINT32_C(250000), UINT32_C(125000) }; - - var1 = (int64_t) ((1340 + (5 * (int64_t) dev->calib.range_sw_err)) * - ((int64_t) lookupTable1[gas_range])) >> 16; - var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1); - var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9); - calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2); - - return calc_gas_res; -} - -/*! - * @brief This internal API is used to calculate the Heat Resistance value. - */ -static uint8_t calc_heater_res(uint16_t temp, const struct bme680_dev *dev) -{ - uint8_t heatr_res; - int32_t var1; - int32_t var2; - int32_t var3; - int32_t var4; - int32_t var5; - int32_t heatr_res_x100; - - if (temp > 400) /* Cap temperature */ - temp = 400; - - var1 = (((int32_t) dev->amb_temp * dev->calib.par_gh3) / 1000) * 256; - var2 = (dev->calib.par_gh1 + 784) * (((((dev->calib.par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); - var3 = var1 + (var2 / 2); - var4 = (var3 / (dev->calib.res_heat_range + 4)); - var5 = (131 * dev->calib.res_heat_val) + 65536; - heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34); - heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100); - - return heatr_res; -} - -#else - - -/*! - * @brief This internal API is used to calculate the - * temperature value in float format - */ -static float calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) -{ - float var1 = 0; - float var2 = 0; - float calc_temp = 0; - - /* calculate var1 data */ - var1 = ((((float)temp_adc / 16384.0f) - ((float)dev->calib.par_t1 / 1024.0f)) - * ((float)dev->calib.par_t2)); - - /* calculate var2 data */ - var2 = (((((float)temp_adc / 131072.0f) - ((float)dev->calib.par_t1 / 8192.0f)) * - (((float)temp_adc / 131072.0f) - ((float)dev->calib.par_t1 / 8192.0f))) * - ((float)dev->calib.par_t3 * 16.0f)); - - /* t_fine value*/ - dev->calib.t_fine = (var1 + var2); - - /* compensated temperature data*/ - calc_temp = ((dev->calib.t_fine) / 5120.0f); - - return calc_temp; -} - -/*! - * @brief This internal API is used to calculate the - * pressure value in float format - */ -static float calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) -{ - float var1 = 0; - float var2 = 0; - float var3 = 0; - float calc_pres = 0; - - var1 = (((float)dev->calib.t_fine / 2.0f) - 64000.0f); - var2 = var1 * var1 * (((float)dev->calib.par_p6) / (131072.0f)); - var2 = var2 + (var1 * ((float)dev->calib.par_p5) * 2.0f); - var2 = (var2 / 4.0f) + (((float)dev->calib.par_p4) * 65536.0f); - var1 = (((((float)dev->calib.par_p3 * var1 * var1) / 16384.0f) - + ((float)dev->calib.par_p2 * var1)) / 524288.0f); - var1 = ((1.0f + (var1 / 32768.0f)) * ((float)dev->calib.par_p1)); - calc_pres = (1048576.0f - ((float)pres_adc)); - - /* Avoid exception caused by division by zero */ - if ((int)var1 != 0) { - calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); - var1 = (((float)dev->calib.par_p9) * calc_pres * calc_pres) / 2147483648.0f; - var2 = calc_pres * (((float)dev->calib.par_p8) / 32768.0f); - var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) - * (dev->calib.par_p10 / 131072.0f)); - calc_pres = (calc_pres + (var1 + var2 + var3 + ((float)dev->calib.par_p7 * 128.0f)) / 16.0f); - } else { - calc_pres = 0; - } - - return calc_pres; -} - -/*! - * @brief This internal API is used to calculate the - * humidity value in float format - */ -static float calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) -{ - float calc_hum = 0; - float var1 = 0; - float var2 = 0; - float var3 = 0; - float var4 = 0; - float temp_comp; - - /* compensated temperature data*/ - temp_comp = ((dev->calib.t_fine) / 5120.0f); - - var1 = (float)((float)hum_adc) - (((float)dev->calib.par_h1 * 16.0f) + (((float)dev->calib.par_h3 / 2.0f) - * temp_comp)); - - var2 = var1 * ((float)(((float) dev->calib.par_h2 / 262144.0f) * (1.0f + (((float)dev->calib.par_h4 / 16384.0f) - * temp_comp) + (((float)dev->calib.par_h5 / 1048576.0f) * temp_comp * temp_comp)))); - - var3 = (float) dev->calib.par_h6 / 16384.0f; - - var4 = (float) dev->calib.par_h7 / 2097152.0f; - - calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); - - if (calc_hum > 100.0f) - calc_hum = 100.0f; - else if (calc_hum < 0.0f) - calc_hum = 0.0f; - - return calc_hum; -} - -/*! - * @brief This internal API is used to calculate the - * gas resistance value in float format - */ -static float calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev) -{ - float calc_gas_res; - float var1 = 0; - float var2 = 0; - float var3 = 0; - - const float lookup_k1_range[16] = { - 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -0.8, - 0.0, 0.0, -0.2, -0.5, 0.0, -1.0, 0.0, 0.0}; - const float lookup_k2_range[16] = { - 0.0, 0.0, 0.0, 0.0, 0.1, 0.7, 0.0, -0.8, - -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - - var1 = (1340.0f + (5.0f * dev->calib.range_sw_err)); - var2 = (var1) * (1.0f + lookup_k1_range[gas_range]/100.0f); - var3 = 1.0f + (lookup_k2_range[gas_range]/100.0f); - - calc_gas_res = 1.0f / (float)(var3 * (0.000000125f) * (float)(1 << gas_range) * (((((float)gas_res_adc) - - 512.0f)/var2) + 1.0f)); - - return calc_gas_res; -} - -/*! - * @brief This internal API is used to calculate the - * heater resistance value in float format - */ -static float calc_heater_res(uint16_t temp, const struct bme680_dev *dev) -{ - float var1 = 0; - float var2 = 0; - float var3 = 0; - float var4 = 0; - float var5 = 0; - float res_heat = 0; - - if (temp > 400) /* Cap temperature */ - temp = 400; - - var1 = (((float)dev->calib.par_gh1 / (16.0f)) + 49.0f); - var2 = ((((float)dev->calib.par_gh2 / (32768.0f)) * (0.0005f)) + 0.00235f); - var3 = ((float)dev->calib.par_gh3 / (1024.0f)); - var4 = (var1 * (1.0f + (var2 * (float)temp))); - var5 = (var4 + (var3 * (float)dev->amb_temp)); - res_heat = (uint8_t)(3.4f * ((var5 * (4 / (4 + (float)dev->calib.res_heat_range)) * - (1/(1 + ((float) dev->calib.res_heat_val * 0.002f)))) - 25)); - - return res_heat; -} - -#endif - -/*! - * @brief This internal API is used to calculate the Heat duration value. - */ -static uint8_t calc_heater_dur(uint16_t dur) -{ - uint8_t factor = 0; - uint8_t durval; - - if (dur >= 0xfc0) { - durval = 0xff; /* Max duration*/ - } else { - while (dur > 0x3F) { - dur = dur / 4; - factor += 1; - } - durval = (uint8_t) (dur + (factor * 64)); - } - - return durval; -} - -/*! - * @brief This internal API is used to calculate the field data of sensor. - */ -static int8_t read_field_data(struct bme680_field_data *data, struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t buff[BME680_FIELD_LENGTH] = { 0 }; - uint8_t gas_range; - uint32_t adc_temp; - uint32_t adc_pres; - uint16_t adc_hum; - uint16_t adc_gas_res; - uint8_t tries = 10; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - do { - if (rslt == BME680_OK) { - rslt = bme680_get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH, - dev); - - data->status = buff[0] & BME680_NEW_DATA_MSK; - data->gas_index = buff[0] & BME680_GAS_INDEX_MSK; - data->meas_index = buff[1]; - - /* read the raw data from the sensor */ - adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16) - | ((uint32_t) buff[4] / 16)); - adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16) - | ((uint32_t) buff[7] / 16)); - adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]); - adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64)); - gas_range = buff[14] & BME680_GAS_RANGE_MSK; - - data->status |= buff[14] & BME680_GASM_VALID_MSK; - data->status |= buff[14] & BME680_HEAT_STAB_MSK; - - if (data->status & BME680_NEW_DATA_MSK) { - data->temperature = calc_temperature(adc_temp, dev); - data->pressure = calc_pressure(adc_pres, dev); - data->humidity = calc_humidity(adc_hum, dev); - data->gas_resistance = calc_gas_resistance(adc_gas_res, gas_range, dev); - break; - } - /* Delay to poll the data */ - dev->delay_ms(BME680_POLL_PERIOD_MS); - } - tries--; - } while (tries); - - if (!tries) - rslt = BME680_W_NO_NEW_DATA; - - return rslt; -} - -/*! - * @brief This internal API is used to set the memory page based on register address. - */ -static int8_t set_mem_page(uint8_t reg_addr, struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t reg; - uint8_t mem_page; - - /* Check for null pointers in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - if (reg_addr > 0x7f) - mem_page = BME680_MEM_PAGE1; - else - mem_page = BME680_MEM_PAGE0; - - if (mem_page != dev->mem_page) { - dev->mem_page = mem_page; - - dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); - if (dev->com_rslt != 0) - rslt = BME680_E_COM_FAIL; - - if (rslt == BME680_OK) { - reg = reg & (~BME680_MEM_PAGE_MSK); - reg = reg | (dev->mem_page & BME680_MEM_PAGE_MSK); - - dev->com_rslt = dev->write(dev->dev_id, BME680_MEM_PAGE_ADDR & BME680_SPI_WR_MSK, - ®, 1); - if (dev->com_rslt != 0) - rslt = BME680_E_COM_FAIL; - } - } - } - - return rslt; -} - -/*! - * @brief This internal API is used to get the memory page based on register address. - */ -static int8_t get_mem_page(struct bme680_dev *dev) -{ - int8_t rslt; - uint8_t reg; - - /* Check for null pointer in the device structure*/ - rslt = null_ptr_check(dev); - if (rslt == BME680_OK) { - dev->com_rslt = dev->read(dev->dev_id, BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); - if (dev->com_rslt != 0) - rslt = BME680_E_COM_FAIL; - else - dev->mem_page = reg & BME680_MEM_PAGE_MSK; - } - - return rslt; -} - -/*! - * @brief This internal API is used to validate the boundary - * conditions. - */ -static int8_t boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev) -{ - int8_t rslt = BME680_OK; - - if (value != NULL) { - /* Check if value is below minimum value */ - if (*value < min) { - /* Auto correct the invalid value to minimum value */ - *value = min; - dev->info_msg |= BME680_I_MIN_CORRECTION; - } - /* Check if value is above maximum value */ - if (*value > max) { - /* Auto correct the invalid value to maximum value */ - *value = max; - dev->info_msg |= BME680_I_MAX_CORRECTION; - } - } else { - rslt = BME680_E_NULL_PTR; - } - - return rslt; -} - -/*! - * @brief This internal API is used to validate the device structure pointer for - * null conditions. - */ -static int8_t null_ptr_check(const struct bme680_dev *dev) -{ - int8_t rslt; - - if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { - /* Device structure pointer is not valid */ - rslt = BME680_E_NULL_PTR; - } else { - /* Device structure is fine */ - rslt = BME680_OK; - } - - return rslt; -} diff --git a/src/bme680/bme680.h b/src/bme680/bme680.h deleted file mode 100644 index f436215..0000000 --- a/src/bme680/bme680.h +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. - * - * BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @file bme680.h - * @date 23 Jan 2020 - * @version 3.5.10 - * @brief - * - */ -/*! @file bme680.h - @brief Sensor driver for BME680 sensor */ -/*! - * @defgroup BME680 SENSOR API - * @{*/ -#ifndef BME680_H_ -#define BME680_H_ - -/*! CPP guard */ -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Header includes */ -#include "bme680_defs.h" - -/* function prototype declarations */ -/*! - * @brief This API is the entry point. - * It reads the chip-id and calibration data from the sensor. - * - * @param[in,out] dev : Structure instance of bme680_dev - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_init(struct bme680_dev *dev); - -/*! - * @brief This API writes the given data to the register address - * of the sensor. - * - * @param[in] reg_addr : Register address from where the data to be written. - * @param[in] reg_data : Pointer to data buffer which is to be written - * in the sensor. - * @param[in] len : No of bytes of data to write.. - * @param[in] dev : Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev); - -/*! - * @brief This API reads the data from the given register address of the sensor. - * - * @param[in] reg_addr : Register address from where the data to be read - * @param[out] reg_data : Pointer to data buffer to store the read data. - * @param[in] len : No of bytes of data to be read. - * @param[in] dev : Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev); - -/*! - * @brief This API performs the soft reset of the sensor. - * - * @param[in] dev : Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. - */ -int8_t bme680_soft_reset(struct bme680_dev *dev); - -/*! - * @brief This API is used to set the power mode of the sensor. - * - * @param[in] dev : Structure instance of bme680_dev - * @note : Pass the value to bme680_dev.power_mode structure variable. - * - * value | mode - * -------------|------------------ - * 0x00 | BME680_SLEEP_MODE - * 0x01 | BME680_FORCED_MODE - * - * * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_set_sensor_mode(struct bme680_dev *dev); - -/*! - * @brief This API is used to get the power mode of the sensor. - * - * @param[in] dev : Structure instance of bme680_dev - * @note : bme680_dev.power_mode structure variable hold the power mode. - * - * value | mode - * ---------|------------------ - * 0x00 | BME680_SLEEP_MODE - * 0x01 | BME680_FORCED_MODE - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_get_sensor_mode(struct bme680_dev *dev); - -/*! - * @brief This API is used to set the profile duration of the sensor. - * - * @param[in] dev : Structure instance of bme680_dev. - * @param[in] duration : Duration of the measurement in ms. - * - * @return Nothing - */ -void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev); - -/*! - * @brief This API is used to get the profile duration of the sensor. - * - * @param[in] dev : Structure instance of bme680_dev. - * @param[in] duration : Duration of the measurement in ms. - * - * @return Nothing - */ -void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev); - -/*! - * @brief This API reads the pressure, temperature and humidity and gas data - * from the sensor, compensates the data and store it in the bme680_data - * structure instance passed by the user. - * - * @param[out] data: Structure instance to hold the data. - * @param[in] dev : Structure instance of bme680_dev. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error - */ -int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev); - -/*! - * @brief This API is used to set the oversampling, filter and T,P,H, gas selection - * settings in the sensor. - * - * @param[in] dev : Structure instance of bme680_dev. - * @param[in] desired_settings : Variable used to select the settings which - * are to be set in the sensor. - * - * Macros | Functionality - *---------------------------------|---------------------------------------------- - * BME680_OST_SEL | To set temperature oversampling. - * BME680_OSP_SEL | To set pressure oversampling. - * BME680_OSH_SEL | To set humidity oversampling. - * BME680_GAS_MEAS_SEL | To set gas measurement setting. - * BME680_FILTER_SEL | To set filter setting. - * BME680_HCNTRL_SEL | To set humidity control setting. - * BME680_RUN_GAS_SEL | To set run gas setting. - * BME680_NBCONV_SEL | To set NB conversion setting. - * BME680_GAS_SENSOR_SEL | To set all gas sensor related settings - * - * @note : Below are the macros to be used by the user for selecting the - * desired settings. User can do OR operation of these macros for configuring - * multiple settings. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. - */ -int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); - -/*! - * @brief This API is used to get the oversampling, filter and T,P,H, gas selection - * settings in the sensor. - * - * @param[in] dev : Structure instance of bme680_dev. - * @param[in] desired_settings : Variable used to select the settings which - * are to be get from the sensor. - * - * @return Result of API execution status - * @retval zero -> Success / +ve value -> Warning / -ve value -> Error. - */ -int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev); -#ifdef __cplusplus -} -#endif /* End of CPP guard */ -#endif /* BME680_H_ */ -/** @}*/ diff --git a/src/bme680/bme680_defs.h b/src/bme680/bme680_defs.h deleted file mode 100644 index 429775d..0000000 --- a/src/bme680/bme680_defs.h +++ /dev/null @@ -1,536 +0,0 @@ -/** - * Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. - * - * BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @file bme680_defs.h - * @date 23 Jan 2020 - * @version 3.5.10 - * @brief - * - */ - -/*! @file bme680_defs.h - @brief Sensor driver for BME680 sensor */ -/*! - * @defgroup BME680 SENSOR API - * @brief - * @{*/ -#ifndef BME680_DEFS_H_ -#define BME680_DEFS_H_ - -/********************************************************/ -/* header includes */ -#ifdef __KERNEL__ -#include -#include -#else -#include -#include -#endif - -/******************************************************************************/ -/*! @name Common macros */ -/******************************************************************************/ - -#if !defined(UINT8_C) && !defined(INT8_C) -#define INT8_C(x) S8_C(x) -#define UINT8_C(x) U8_C(x) -#endif - -#if !defined(UINT16_C) && !defined(INT16_C) -#define INT16_C(x) S16_C(x) -#define UINT16_C(x) U16_C(x) -#endif - -#if !defined(INT32_C) && !defined(UINT32_C) -#define INT32_C(x) S32_C(x) -#define UINT32_C(x) U32_C(x) -#endif - -#if !defined(INT64_C) && !defined(UINT64_C) -#define INT64_C(x) S64_C(x) -#define UINT64_C(x) U64_C(x) -#endif - -/**@}*/ - -/**\name C standard macros */ -#ifndef NULL -#ifdef __cplusplus -#define NULL 0 -#else -#define NULL ((void *) 0) -#endif -#endif - -/** BME680 configuration macros */ -/** Enable or un-comment the macro to provide floating point data output */ -#ifndef BME680_FLOAT_POINT_COMPENSATION -/* #define BME680_FLOAT_POINT_COMPENSATION */ -#endif - -/** BME680 General config */ -#define BME680_POLL_PERIOD_MS UINT8_C(10) - -/** BME680 I2C addresses */ -#define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76) -#define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77) - -/** BME680 unique chip identifier */ -#define BME680_CHIP_ID UINT8_C(0x61) - -/** BME680 coefficients related defines */ -#define BME680_COEFF_SIZE UINT8_C(41) -#define BME680_COEFF_ADDR1_LEN UINT8_C(25) -#define BME680_COEFF_ADDR2_LEN UINT8_C(16) - -/** BME680 field_x related defines */ -#define BME680_FIELD_LENGTH UINT8_C(15) -#define BME680_FIELD_ADDR_OFFSET UINT8_C(17) - -/** Soft reset command */ -#define BME680_SOFT_RESET_CMD UINT8_C(0xb6) - -/** Error code definitions */ -#define BME680_OK INT8_C(0) -/* Errors */ -#define BME680_E_NULL_PTR INT8_C(-1) -#define BME680_E_COM_FAIL INT8_C(-2) -#define BME680_E_DEV_NOT_FOUND INT8_C(-3) -#define BME680_E_INVALID_LENGTH INT8_C(-4) - -/* Warnings */ -#define BME680_W_DEFINE_PWR_MODE INT8_C(1) -#define BME680_W_NO_NEW_DATA INT8_C(2) - -/* Info's */ -#define BME680_I_MIN_CORRECTION UINT8_C(1) -#define BME680_I_MAX_CORRECTION UINT8_C(2) - -/** Register map */ -/** Other coefficient's address */ -#define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00) -#define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02) -#define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04) -#define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A) -#define BME680_ADDR_GAS_CONF_START UINT8_C(0x64) - -/** Field settings */ -#define BME680_FIELD0_ADDR UINT8_C(0x1d) - -/** Heater settings */ -#define BME680_RES_HEAT0_ADDR UINT8_C(0x5a) -#define BME680_GAS_WAIT0_ADDR UINT8_C(0x64) - -/** Sensor configuration registers */ -#define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70) -#define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71) -#define BME680_CONF_OS_H_ADDR UINT8_C(0x72) -#define BME680_MEM_PAGE_ADDR UINT8_C(0xf3) -#define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74) -#define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75) - -/** Coefficient's address */ -#define BME680_COEFF_ADDR1 UINT8_C(0x89) -#define BME680_COEFF_ADDR2 UINT8_C(0xe1) - -/** Chip identifier */ -#define BME680_CHIP_ID_ADDR UINT8_C(0xd0) - -/** Soft reset register */ -#define BME680_SOFT_RESET_ADDR UINT8_C(0xe0) - -/** Heater control settings */ -#define BME680_ENABLE_HEATER UINT8_C(0x00) -#define BME680_DISABLE_HEATER UINT8_C(0x08) - -/** Gas measurement settings */ -#define BME680_DISABLE_GAS_MEAS UINT8_C(0x00) -#define BME680_ENABLE_GAS_MEAS UINT8_C(0x01) - -/** Over-sampling settings */ -#define BME680_OS_NONE UINT8_C(0) -#define BME680_OS_1X UINT8_C(1) -#define BME680_OS_2X UINT8_C(2) -#define BME680_OS_4X UINT8_C(3) -#define BME680_OS_8X UINT8_C(4) -#define BME680_OS_16X UINT8_C(5) - -/** IIR filter settings */ -#define BME680_FILTER_SIZE_0 UINT8_C(0) -#define BME680_FILTER_SIZE_1 UINT8_C(1) -#define BME680_FILTER_SIZE_3 UINT8_C(2) -#define BME680_FILTER_SIZE_7 UINT8_C(3) -#define BME680_FILTER_SIZE_15 UINT8_C(4) -#define BME680_FILTER_SIZE_31 UINT8_C(5) -#define BME680_FILTER_SIZE_63 UINT8_C(6) -#define BME680_FILTER_SIZE_127 UINT8_C(7) - -/** Power mode settings */ -#define BME680_SLEEP_MODE UINT8_C(0) -#define BME680_FORCED_MODE UINT8_C(1) - -/** Delay related macro declaration */ -#define BME680_RESET_PERIOD UINT32_C(10) - -/** SPI memory page settings */ -#define BME680_MEM_PAGE0 UINT8_C(0x10) -#define BME680_MEM_PAGE1 UINT8_C(0x00) - -/** Ambient humidity shift value for compensation */ -#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) - -/** Run gas enable and disable settings */ -#define BME680_RUN_GAS_DISABLE UINT8_C(0) -#define BME680_RUN_GAS_ENABLE UINT8_C(1) - -/** Buffer length macro declaration */ -#define BME680_TMP_BUFFER_LENGTH UINT8_C(40) -#define BME680_REG_BUFFER_LENGTH UINT8_C(6) -#define BME680_FIELD_DATA_LENGTH UINT8_C(3) -#define BME680_GAS_REG_BUF_LENGTH UINT8_C(20) - -/** Settings selector */ -#define BME680_OST_SEL UINT16_C(1) -#define BME680_OSP_SEL UINT16_C(2) -#define BME680_OSH_SEL UINT16_C(4) -#define BME680_GAS_MEAS_SEL UINT16_C(8) -#define BME680_FILTER_SEL UINT16_C(16) -#define BME680_HCNTRL_SEL UINT16_C(32) -#define BME680_RUN_GAS_SEL UINT16_C(64) -#define BME680_NBCONV_SEL UINT16_C(128) -#define BME680_GAS_SENSOR_SEL (BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL) - -/** Number of conversion settings*/ -#define BME680_NBCONV_MIN UINT8_C(0) -#define BME680_NBCONV_MAX UINT8_C(10) - -/** Mask definitions */ -#define BME680_GAS_MEAS_MSK UINT8_C(0x30) -#define BME680_NBCONV_MSK UINT8_C(0X0F) -#define BME680_FILTER_MSK UINT8_C(0X1C) -#define BME680_OST_MSK UINT8_C(0XE0) -#define BME680_OSP_MSK UINT8_C(0X1C) -#define BME680_OSH_MSK UINT8_C(0X07) -#define BME680_HCTRL_MSK UINT8_C(0x08) -#define BME680_RUN_GAS_MSK UINT8_C(0x10) -#define BME680_MODE_MSK UINT8_C(0x03) -#define BME680_RHRANGE_MSK UINT8_C(0x30) -#define BME680_RSERROR_MSK UINT8_C(0xf0) -#define BME680_NEW_DATA_MSK UINT8_C(0x80) -#define BME680_GAS_INDEX_MSK UINT8_C(0x0f) -#define BME680_GAS_RANGE_MSK UINT8_C(0x0f) -#define BME680_GASM_VALID_MSK UINT8_C(0x20) -#define BME680_HEAT_STAB_MSK UINT8_C(0x10) -#define BME680_MEM_PAGE_MSK UINT8_C(0x10) -#define BME680_SPI_RD_MSK UINT8_C(0x80) -#define BME680_SPI_WR_MSK UINT8_C(0x7f) -#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) - -/** Bit position definitions for sensor settings */ -#define BME680_GAS_MEAS_POS UINT8_C(4) -#define BME680_FILTER_POS UINT8_C(2) -#define BME680_OST_POS UINT8_C(5) -#define BME680_OSP_POS UINT8_C(2) -#define BME680_RUN_GAS_POS UINT8_C(4) - -/** Array Index to Field data mapping for Calibration Data*/ -#define BME680_T2_LSB_REG (1) -#define BME680_T2_MSB_REG (2) -#define BME680_T3_REG (3) -#define BME680_P1_LSB_REG (5) -#define BME680_P1_MSB_REG (6) -#define BME680_P2_LSB_REG (7) -#define BME680_P2_MSB_REG (8) -#define BME680_P3_REG (9) -#define BME680_P4_LSB_REG (11) -#define BME680_P4_MSB_REG (12) -#define BME680_P5_LSB_REG (13) -#define BME680_P5_MSB_REG (14) -#define BME680_P7_REG (15) -#define BME680_P6_REG (16) -#define BME680_P8_LSB_REG (19) -#define BME680_P8_MSB_REG (20) -#define BME680_P9_LSB_REG (21) -#define BME680_P9_MSB_REG (22) -#define BME680_P10_REG (23) -#define BME680_H2_MSB_REG (25) -#define BME680_H2_LSB_REG (26) -#define BME680_H1_LSB_REG (26) -#define BME680_H1_MSB_REG (27) -#define BME680_H3_REG (28) -#define BME680_H4_REG (29) -#define BME680_H5_REG (30) -#define BME680_H6_REG (31) -#define BME680_H7_REG (32) -#define BME680_T1_LSB_REG (33) -#define BME680_T1_MSB_REG (34) -#define BME680_GH2_LSB_REG (35) -#define BME680_GH2_MSB_REG (36) -#define BME680_GH1_REG (37) -#define BME680_GH3_REG (38) - -/** BME680 register buffer index settings*/ -#define BME680_REG_FILTER_INDEX UINT8_C(5) -#define BME680_REG_TEMP_INDEX UINT8_C(4) -#define BME680_REG_PRES_INDEX UINT8_C(4) -#define BME680_REG_HUM_INDEX UINT8_C(2) -#define BME680_REG_NBCONV_INDEX UINT8_C(1) -#define BME680_REG_RUN_GAS_INDEX UINT8_C(1) -#define BME680_REG_HCTRL_INDEX UINT8_C(0) - -/** BME680 pressure calculation macros */ -/*! This max value is used to provide precedence to multiplication or division - * in pressure compensation equation to achieve least loss of precision and - * avoiding overflows. - * i.e Comparing value, BME680_MAX_OVERFLOW_VAL = INT32_C(1 << 30) - */ -#define BME680_MAX_OVERFLOW_VAL INT32_C(0x40000000) - -/** Macro to combine two 8 bit data's to form a 16 bit data */ -#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) - -/** Macro to SET and GET BITS of a register */ -#define BME680_SET_BITS(reg_data, bitname, data) \ - ((reg_data & ~(bitname##_MSK)) | \ - ((data << bitname##_POS) & bitname##_MSK)) -#define BME680_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \ - (bitname##_POS)) - -/** Macro variant to handle the bitname position if it is zero */ -#define BME680_SET_BITS_POS_0(reg_data, bitname, data) \ - ((reg_data & ~(bitname##_MSK)) | \ - (data & bitname##_MSK)) -#define BME680_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) - -/** Type definitions */ -/*! - * Generic communication function pointer - * @param[in] dev_id: Place holder to store the id of the device structure - * Can be used to store the index of the Chip select or - * I2C address of the device. - * @param[in] reg_addr: Used to select the register the where data needs to - * be read from or written to. - * @param[in/out] reg_data: Data array to read/write - * @param[in] len: Length of the data array - */ -typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len); - -/*! - * Delay function pointer - * @param[in] period: Time period in milliseconds - */ -typedef void (*bme680_delay_fptr_t)(uint32_t period); - -/*! - * @brief Interface selection Enumerations - */ -enum bme680_intf { - /*! SPI interface */ - BME680_SPI_INTF, - /*! I2C interface */ - BME680_I2C_INTF -}; - -/* structure definitions */ -/*! - * @brief Sensor field data structure - */ -struct bme680_field_data { - /*! Contains new_data, gasm_valid & heat_stab */ - uint8_t status; - /*! The index of the heater profile used */ - uint8_t gas_index; - /*! Measurement index to track order */ - uint8_t meas_index; - -#ifndef BME680_FLOAT_POINT_COMPENSATION - /*! Temperature in degree celsius x100 */ - int16_t temperature; - /*! Pressure in Pascal */ - uint32_t pressure; - /*! Humidity in % relative humidity x1000 */ - uint32_t humidity; - /*! Gas resistance in Ohms */ - uint32_t gas_resistance; -#else - /*! Temperature in degree celsius */ - float temperature; - /*! Pressure in Pascal */ - float pressure; - /*! Humidity in % relative humidity x1000 */ - float humidity; - /*! Gas resistance in Ohms */ - float gas_resistance; - -#endif - -}; - -/*! - * @brief Structure to hold the Calibration data - */ -struct bme680_calib_data { - /*! Variable to store calibrated humidity data */ - uint16_t par_h1; - /*! Variable to store calibrated humidity data */ - uint16_t par_h2; - /*! Variable to store calibrated humidity data */ - int8_t par_h3; - /*! Variable to store calibrated humidity data */ - int8_t par_h4; - /*! Variable to store calibrated humidity data */ - int8_t par_h5; - /*! Variable to store calibrated humidity data */ - uint8_t par_h6; - /*! Variable to store calibrated humidity data */ - int8_t par_h7; - /*! Variable to store calibrated gas data */ - int8_t par_gh1; - /*! Variable to store calibrated gas data */ - int16_t par_gh2; - /*! Variable to store calibrated gas data */ - int8_t par_gh3; - /*! Variable to store calibrated temperature data */ - uint16_t par_t1; - /*! Variable to store calibrated temperature data */ - int16_t par_t2; - /*! Variable to store calibrated temperature data */ - int8_t par_t3; - /*! Variable to store calibrated pressure data */ - uint16_t par_p1; - /*! Variable to store calibrated pressure data */ - int16_t par_p2; - /*! Variable to store calibrated pressure data */ - int8_t par_p3; - /*! Variable to store calibrated pressure data */ - int16_t par_p4; - /*! Variable to store calibrated pressure data */ - int16_t par_p5; - /*! Variable to store calibrated pressure data */ - int8_t par_p6; - /*! Variable to store calibrated pressure data */ - int8_t par_p7; - /*! Variable to store calibrated pressure data */ - int16_t par_p8; - /*! Variable to store calibrated pressure data */ - int16_t par_p9; - /*! Variable to store calibrated pressure data */ - uint8_t par_p10; - -#ifndef BME680_FLOAT_POINT_COMPENSATION - /*! Variable to store t_fine size */ - int32_t t_fine; -#else - /*! Variable to store t_fine size */ - float t_fine; -#endif - /*! Variable to store heater resistance range */ - uint8_t res_heat_range; - /*! Variable to store heater resistance value */ - int8_t res_heat_val; - /*! Variable to store error range */ - int8_t range_sw_err; -}; - -/*! - * @brief BME680 sensor settings structure which comprises of ODR, - * over-sampling and filter settings. - */ -struct bme680_tph_sett { - /*! Humidity oversampling */ - uint8_t os_hum; - /*! Temperature oversampling */ - uint8_t os_temp; - /*! Pressure oversampling */ - uint8_t os_pres; - /*! Filter coefficient */ - uint8_t filter; -}; - -/*! - * @brief BME680 gas sensor which comprises of gas settings - * and status parameters - */ -struct bme680_gas_sett { - /*! Variable to store nb conversion */ - uint8_t nb_conv; - /*! Variable to store heater control */ - uint8_t heatr_ctrl; - /*! Run gas enable value */ - uint8_t run_gas; - /*! Heater temperature value */ - uint16_t heatr_temp; - /*! Duration profile value */ - uint16_t heatr_dur; -}; - -/*! - * @brief BME680 device structure - */ -struct bme680_dev { - /*! Chip Id */ - uint8_t chip_id; - /*! Device Id */ - uint8_t dev_id; - /*! SPI/I2C interface */ - enum bme680_intf intf; - /*! Memory page used */ - uint8_t mem_page; - /*! Ambient temperature in Degree C */ - int8_t amb_temp; - /*! Sensor calibration data */ - struct bme680_calib_data calib; - /*! Sensor settings */ - struct bme680_tph_sett tph_sett; - /*! Gas Sensor settings */ - struct bme680_gas_sett gas_sett; - /*! Sensor power modes */ - uint8_t power_mode; - /*! New sensor fields */ - uint8_t new_fields; - /*! Store the info messages */ - uint8_t info_msg; - /*! Bus read function pointer */ - bme680_com_fptr_t read; - /*! Bus write function pointer */ - bme680_com_fptr_t write; - /*! delay function pointer */ - bme680_delay_fptr_t delay_ms; - /*! Communication function result */ - int8_t com_rslt; -}; - - - -#endif /* BME680_DEFS_H_ */ -/** @}*/ -/** @}*/ diff --git a/src/bme680/LICENSE b/src/bme68x/LICENSE similarity index 73% rename from src/bme680/LICENSE rename to src/bme68x/LICENSE index df241f2..39d6442 100644 --- a/src/bme680/LICENSE +++ b/src/bme68x/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved. +Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. BSD-3-Clause @@ -6,15 +6,15 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT diff --git a/src/bme68x/README.md b/src/bme68x/README.md new file mode 100644 index 0000000..77f94ff --- /dev/null +++ b/src/bme68x/README.md @@ -0,0 +1,30 @@ +# BME68X Sensor API + +> Bosch Sensortec's BME680 and BME688 sensor API + +## Sensor Overview +BME680 is an integrated environmental sensor developed specifically for mobile applications and wearables where size and low power consumption are key requirements. Expanding Bosch Sensortec’s existing family of environmental sensors, the BME680 integrates for the first time high-linearity and high-accuracy gas, pressure, humidity and temperature sensors. It consists of an 8-pin metal-lid 3.0 x 3.0 x 0.93 mm³ LGA package which is designed for optimized consumption depending on the specific operating mode, long term stability and high EMC robustness. The gas sensor within the BME680 can detect a broad range of gases to measure air quality for personal well being. Gases that can be detected by the BME680 include Volatile Organic Compounds (VOC) from paints (such as formaldehyde), lacquers, paint strippers, cleaning supplies, furnishings, office equipment, glues, adhesives and alcohol. + +### Features + +- Air quality measurement +- Personalized weather station +- Context awareness, e.g. skin moisture detection, room change detection +- Fitness monitoring / well-being +- Warning regarding dryness or high temperatures +- Measurement of volume and air flow +- Home automation control (e.g. HVAC) +- GPS enhancement (e.g. time-to-first-fix improvement, dead reckoning, slope detection) +- Indoor navigation (change of floor detection, elevator detection) +- Altitude tracking and calories expenditure for sports activities + +#### Important links: +For more information, please refer to: + +- [BME680 Product page](https://www.bosch-sensortec.com/bst/products/all_products/bme680) +- [BME680 & BME688 Github page](https://github.com/BoschSensortec/BME68x-Sensor-API) +- [BME680 gas sensor design guide](https://community.bosch-sensortec.com/t5/Knowledge-base/BME680-gas-sensor-series-design-guide/ta-p/5952) +- [Knowledge base page](https://community.bosch-sensortec.com/t5/Knowledge-base/tkb-p/bst_community-mems-tkb) +- [Community support page](https://community.bosch-sensortec.com) + +--- \ No newline at end of file diff --git a/src/bme68x/bme68x.c b/src/bme68x/bme68x.c new file mode 100644 index 0000000..7c3c935 --- /dev/null +++ b/src/bme68x/bme68x.c @@ -0,0 +1,1848 @@ +/** +* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bme68x.c +* @date 2021-11-09 +* @version v4.4.7 +* +*/ + +#include "bme68x.h" +#include + +/* This internal API is used to read the calibration coefficients */ +static int8_t get_calib_data(struct bme68x_dev *dev); + +/* This internal API is used to read variant ID information register status */ +static int8_t read_variant_id(struct bme68x_dev *dev); + +/* This internal API is used to calculate the gas wait */ +static uint8_t calc_gas_wait(uint16_t dur); + +#ifndef BME68X_USE_FPU + +/* This internal API is used to calculate the temperature in integer */ +static int16_t calc_temperature(uint32_t temp_adc, struct bme68x_dev *dev); + +/* This internal API is used to calculate the pressure in integer */ +static uint32_t calc_pressure(uint32_t pres_adc, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the humidity in integer */ +static uint32_t calc_humidity(uint16_t hum_adc, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the gas resistance high */ +static uint32_t calc_gas_resistance_high(uint16_t gas_res_adc, uint8_t gas_range); + +/* This internal API is used to calculate the gas resistance low */ +static uint32_t calc_gas_resistance_low(uint16_t gas_res_adc, uint8_t gas_range, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the heater resistance using integer */ +static uint8_t calc_res_heat(uint16_t temp, const struct bme68x_dev *dev); + +#else + +/* This internal API is used to calculate the temperature value in float */ +static float calc_temperature(uint32_t temp_adc, struct bme68x_dev *dev); + +/* This internal API is used to calculate the pressure value in float */ +static float calc_pressure(uint32_t pres_adc, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the humidity value in float */ +static float calc_humidity(uint16_t hum_adc, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the gas resistance high value in float */ +static float calc_gas_resistance_high(uint16_t gas_res_adc, uint8_t gas_range); + +/* This internal API is used to calculate the gas resistance low value in float */ +static float calc_gas_resistance_low(uint16_t gas_res_adc, uint8_t gas_range, const struct bme68x_dev *dev); + +/* This internal API is used to calculate the heater resistance value using float */ +static uint8_t calc_res_heat(uint16_t temp, const struct bme68x_dev *dev); + +#endif + +/* This internal API is used to read a single data of the sensor */ +static int8_t read_field_data(uint8_t index, struct bme68x_data *data, struct bme68x_dev *dev); + +/* This internal API is used to read all data fields of the sensor */ +static int8_t read_all_field_data(struct bme68x_data * const data[], struct bme68x_dev *dev); + +/* This internal API is used to switch between SPI memory pages */ +static int8_t set_mem_page(uint8_t reg_addr, struct bme68x_dev *dev); + +/* This internal API is used to get the current SPI memory page */ +static int8_t get_mem_page(struct bme68x_dev *dev); + +/* This internal API is used to check the bme68x_dev for null pointers */ +static int8_t null_ptr_check(const struct bme68x_dev *dev); + +/* This internal API is used to set heater configurations */ +static int8_t set_conf(const struct bme68x_heatr_conf *conf, uint8_t op_mode, uint8_t *nb_conv, struct bme68x_dev *dev); + +/* This internal API is used to limit the max value of a parameter */ +static int8_t boundary_check(uint8_t *value, uint8_t max, struct bme68x_dev *dev); + +/* This internal API is used to calculate the register value for + * shared heater duration */ +static uint8_t calc_heatr_dur_shared(uint16_t dur); + +/* This internal API is used to swap two fields */ +static void swap_fields(uint8_t index1, uint8_t index2, struct bme68x_data *field[]); + +/* This internal API is used sort the sensor data */ +static void sort_sensor_data(uint8_t low_index, uint8_t high_index, struct bme68x_data *field[]); + +/* + * @brief Function to analyze the sensor data + * + * @param[in] data Array of measurement data + * @param[in] n_meas Number of measurements + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +static int8_t analyze_sensor_data(const struct bme68x_data *data, uint8_t n_meas); + +/******************************************************************************************/ +/* Global API definitions */ +/******************************************************************************************/ + +/* @brief This API reads the chip-id of the sensor which is the first step to +* verify the sensor and also calibrates the sensor +* As this API is the entry point, call this API before using other APIs. +*/ +int8_t bme68x_init(struct bme68x_dev *dev) +{ + int8_t rslt; + + rslt = bme68x_soft_reset(dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_CHIP_ID, &dev->chip_id, 1, dev); + if (rslt == BME68X_OK) + { + if (dev->chip_id == BME68X_CHIP_ID) + { + /* Read Variant ID */ + rslt = read_variant_id(dev); + + if (rslt == BME68X_OK) + { + /* Get the Calibration data */ + rslt = get_calib_data(dev); + } + } + else + { + rslt = BME68X_E_DEV_NOT_FOUND; + } + } + } + + return rslt; +} + +/* + * @brief This API writes the given data to the register address of the sensor + */ +int8_t bme68x_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev) +{ + int8_t rslt; + + /* Length of the temporary buffer is 2*(length of register)*/ + uint8_t tmp_buff[BME68X_LEN_INTERLEAVE_BUFF] = { 0 }; + uint16_t index; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + if ((rslt == BME68X_OK) && reg_addr && reg_data) + { + if ((len > 0) && (len <= (BME68X_LEN_INTERLEAVE_BUFF / 2))) + { + /* Interleave the 2 arrays */ + for (index = 0; index < len; index++) + { + if (dev->intf == BME68X_SPI_INTF) + { + /* Set the memory page */ + rslt = set_mem_page(reg_addr[index], dev); + tmp_buff[(2 * index)] = reg_addr[index] & BME68X_SPI_WR_MSK; + } + else + { + tmp_buff[(2 * index)] = reg_addr[index]; + } + + tmp_buff[(2 * index) + 1] = reg_data[index]; + } + + /* Write the interleaved array */ + if (rslt == BME68X_OK) + { + dev->intf_rslt = dev->write(tmp_buff[0], &tmp_buff[1], (2 * len) - 1, dev->intf_ptr); + if (dev->intf_rslt != 0) + { + rslt = BME68X_E_COM_FAIL; + } + } + } + else + { + rslt = BME68X_E_INVALID_LENGTH; + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* + * @brief This API reads the data from the given register address of sensor. + */ +int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + if ((rslt == BME68X_OK) && reg_data) + { + if (dev->intf == BME68X_SPI_INTF) + { + /* Set the memory page */ + rslt = set_mem_page(reg_addr, dev); + if (rslt == BME68X_OK) + { + reg_addr = reg_addr | BME68X_SPI_RD_MSK; + } + } + + dev->intf_rslt = dev->read(reg_addr, reg_data, len, dev->intf_ptr); + if (dev->intf_rslt != 0) + { + rslt = BME68X_E_COM_FAIL; + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* + * @brief This API soft-resets the sensor. + */ +int8_t bme68x_soft_reset(struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t reg_addr = BME68X_REG_SOFT_RESET; + + /* 0xb6 is the soft reset command */ + uint8_t soft_rst_cmd = BME68X_SOFT_RESET_CMD; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + if (rslt == BME68X_OK) + { + if (dev->intf == BME68X_SPI_INTF) + { + rslt = get_mem_page(dev); + } + + /* Reset the device */ + if (rslt == BME68X_OK) + { + rslt = bme68x_set_regs(®_addr, &soft_rst_cmd, 1, dev); + + /* Wait for 5ms */ + dev->delay_us(BME68X_PERIOD_RESET, dev->intf_ptr); + if (rslt == BME68X_OK) + { + /* After reset get the memory page */ + if (dev->intf == BME68X_SPI_INTF) + { + rslt = get_mem_page(dev); + } + } + } + } + + return rslt; +} + +/* + * @brief This API is used to set the oversampling, filter and odr configuration + */ +int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t odr20 = 0, odr3 = 1; + uint8_t current_op_mode; + + /* Register data starting from BME68X_REG_CTRL_GAS_1(0x71) up to BME68X_REG_CONFIG(0x75) */ + uint8_t reg_array[BME68X_LEN_CONFIG] = { 0x71, 0x72, 0x73, 0x74, 0x75 }; + uint8_t data_array[BME68X_LEN_CONFIG] = { 0 }; + + rslt = bme68x_get_op_mode(¤t_op_mode, dev); + if (rslt == BME68X_OK) + { + /* Configure only in the sleep mode */ + rslt = bme68x_set_op_mode(BME68X_SLEEP_MODE, dev); + } + + if (conf == NULL) + { + rslt = BME68X_E_NULL_PTR; + } + else if (rslt == BME68X_OK) + { + /* Read the whole configuration and write it back once later */ + rslt = bme68x_get_regs(reg_array[0], data_array, BME68X_LEN_CONFIG, dev); + dev->info_msg = BME68X_OK; + if (rslt == BME68X_OK) + { + rslt = boundary_check(&conf->filter, BME68X_FILTER_SIZE_127, dev); + } + + if (rslt == BME68X_OK) + { + rslt = boundary_check(&conf->os_temp, BME68X_OS_16X, dev); + } + + if (rslt == BME68X_OK) + { + rslt = boundary_check(&conf->os_pres, BME68X_OS_16X, dev); + } + + if (rslt == BME68X_OK) + { + rslt = boundary_check(&conf->os_hum, BME68X_OS_16X, dev); + } + + if (rslt == BME68X_OK) + { + rslt = boundary_check(&conf->odr, BME68X_ODR_NONE, dev); + } + + if (rslt == BME68X_OK) + { + data_array[4] = BME68X_SET_BITS(data_array[4], BME68X_FILTER, conf->filter); + data_array[3] = BME68X_SET_BITS(data_array[3], BME68X_OST, conf->os_temp); + data_array[3] = BME68X_SET_BITS(data_array[3], BME68X_OSP, conf->os_pres); + data_array[1] = BME68X_SET_BITS_POS_0(data_array[1], BME68X_OSH, conf->os_hum); + if (conf->odr != BME68X_ODR_NONE) + { + odr20 = conf->odr; + odr3 = 0; + } + + data_array[4] = BME68X_SET_BITS(data_array[4], BME68X_ODR20, odr20); + data_array[0] = BME68X_SET_BITS(data_array[0], BME68X_ODR3, odr3); + } + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_set_regs(reg_array, data_array, BME68X_LEN_CONFIG, dev); + } + + if ((current_op_mode != BME68X_SLEEP_MODE) && (rslt == BME68X_OK)) + { + rslt = bme68x_set_op_mode(current_op_mode, dev); + } + + return rslt; +} + +/* + * @brief This API is used to get the oversampling, filter and odr + */ +int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev) +{ + int8_t rslt; + + /* starting address of the register array for burst read*/ + uint8_t reg_addr = BME68X_REG_CTRL_GAS_1; + uint8_t data_array[BME68X_LEN_CONFIG]; + + rslt = bme68x_get_regs(reg_addr, data_array, 5, dev); + if (!conf) + { + rslt = BME68X_E_NULL_PTR; + } + else if (rslt == BME68X_OK) + { + conf->os_hum = BME68X_GET_BITS_POS_0(data_array[1], BME68X_OSH); + conf->filter = BME68X_GET_BITS(data_array[4], BME68X_FILTER); + conf->os_temp = BME68X_GET_BITS(data_array[3], BME68X_OST); + conf->os_pres = BME68X_GET_BITS(data_array[3], BME68X_OSP); + if (BME68X_GET_BITS(data_array[0], BME68X_ODR3)) + { + conf->odr = BME68X_ODR_NONE; + } + else + { + conf->odr = BME68X_GET_BITS(data_array[4], BME68X_ODR20); + } + } + + return rslt; +} + +/* + * @brief This API is used to set the operation mode of the sensor + */ +int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t tmp_pow_mode; + uint8_t pow_mode = 0; + uint8_t reg_addr = BME68X_REG_CTRL_MEAS; + + /* Call until in sleep */ + do + { + rslt = bme68x_get_regs(BME68X_REG_CTRL_MEAS, &tmp_pow_mode, 1, dev); + if (rslt == BME68X_OK) + { + /* Put to sleep before changing mode */ + pow_mode = (tmp_pow_mode & BME68X_MODE_MSK); + if (pow_mode != BME68X_SLEEP_MODE) + { + tmp_pow_mode &= ~BME68X_MODE_MSK; /* Set to sleep */ + rslt = bme68x_set_regs(®_addr, &tmp_pow_mode, 1, dev); + dev->delay_us(BME68X_PERIOD_POLL, dev->intf_ptr); + } + } + } while ((pow_mode != BME68X_SLEEP_MODE) && (rslt == BME68X_OK)); + + /* Already in sleep */ + if ((op_mode != BME68X_SLEEP_MODE) && (rslt == BME68X_OK)) + { + tmp_pow_mode = (tmp_pow_mode & ~BME68X_MODE_MSK) | (op_mode & BME68X_MODE_MSK); + rslt = bme68x_set_regs(®_addr, &tmp_pow_mode, 1, dev); + } + + return rslt; +} + +/* + * @brief This API is used to get the operation mode of the sensor. + */ +int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t mode; + + if (op_mode) + { + rslt = bme68x_get_regs(BME68X_REG_CTRL_MEAS, &mode, 1, dev); + + /* Masking the other register bit info*/ + *op_mode = mode & BME68X_MODE_MSK; + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* + * @brief This API is used to get the remaining duration that can be used for heating. + */ +uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev) +{ + int8_t rslt; + uint32_t meas_dur = 0; /* Calculate in us */ + uint32_t meas_cycles; + uint8_t os_to_meas_cycles[6] = { 0, 1, 2, 4, 8, 16 }; + + if (conf != NULL) + { + /* Boundary check for temperature oversampling */ + rslt = boundary_check(&conf->os_temp, BME68X_OS_16X, dev); + + if (rslt == BME68X_OK) + { + /* Boundary check for pressure oversampling */ + rslt = boundary_check(&conf->os_pres, BME68X_OS_16X, dev); + } + + if (rslt == BME68X_OK) + { + /* Boundary check for humidity oversampling */ + rslt = boundary_check(&conf->os_hum, BME68X_OS_16X, dev); + } + + if (rslt == BME68X_OK) + { + meas_cycles = os_to_meas_cycles[conf->os_temp]; + meas_cycles += os_to_meas_cycles[conf->os_pres]; + meas_cycles += os_to_meas_cycles[conf->os_hum]; + + /* TPH measurement duration */ + meas_dur = meas_cycles * UINT32_C(1963); + meas_dur += UINT32_C(477 * 4); /* TPH switching duration */ + meas_dur += UINT32_C(477 * 5); /* Gas measurement duration */ + + if (op_mode != BME68X_PARALLEL_MODE) + { + meas_dur += UINT32_C(1000); /* Wake up duration of 1ms */ + } + } + } + + return meas_dur; +} + +/* + * @brief This API reads the pressure, temperature and humidity and gas data + * from the sensor, compensates the data and store it in the bme68x_data + * structure instance passed by the user. + */ +int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t i = 0, j = 0, new_fields = 0; + struct bme68x_data *field_ptr[3] = { 0 }; + struct bme68x_data field_data[3] = { { 0 } }; + + field_ptr[0] = &field_data[0]; + field_ptr[1] = &field_data[1]; + field_ptr[2] = &field_data[2]; + + rslt = null_ptr_check(dev); + if ((rslt == BME68X_OK) && (data != NULL)) + { + /* Reading the sensor data in forced mode only */ + if (op_mode == BME68X_FORCED_MODE) + { + rslt = read_field_data(0, data, dev); + if (rslt == BME68X_OK) + { + if (data->status & BME68X_NEW_DATA_MSK) + { + new_fields = 1; + } + else + { + new_fields = 0; + rslt = BME68X_W_NO_NEW_DATA; + } + } + } + else if ((op_mode == BME68X_PARALLEL_MODE) || (op_mode == BME68X_SEQUENTIAL_MODE)) + { + /* Read the 3 fields and count the number of new data fields */ + rslt = read_all_field_data(field_ptr, dev); + + new_fields = 0; + for (i = 0; (i < 3) && (rslt == BME68X_OK); i++) + { + if (field_ptr[i]->status & BME68X_NEW_DATA_MSK) + { + new_fields++; + } + } + + /* Sort the sensor data in parallel & sequential modes*/ + for (i = 0; (i < 2) && (rslt == BME68X_OK); i++) + { + for (j = i + 1; j < 3; j++) + { + sort_sensor_data(i, j, field_ptr); + } + } + + /* Copy the sorted data */ + for (i = 0; ((i < 3) && (rslt == BME68X_OK)); i++) + { + data[i] = *field_ptr[i]; + } + + if (new_fields == 0) + { + rslt = BME68X_W_NO_NEW_DATA; + } + } + else + { + rslt = BME68X_W_DEFINE_OP_MODE; + } + + if (n_data == NULL) + { + rslt = BME68X_E_NULL_PTR; + } + else + { + *n_data = new_fields; + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* + * @brief This API is used to set the gas configuration of the sensor. + */ +int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t nb_conv = 0; + uint8_t hctrl, run_gas = 0; + uint8_t ctrl_gas_data[2]; + uint8_t ctrl_gas_addr[2] = { BME68X_REG_CTRL_GAS_0, BME68X_REG_CTRL_GAS_1 }; + + if (conf != NULL) + { + rslt = bme68x_set_op_mode(BME68X_SLEEP_MODE, dev); + if (rslt == BME68X_OK) + { + rslt = set_conf(conf, op_mode, &nb_conv, dev); + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_CTRL_GAS_0, ctrl_gas_data, 2, dev); + if (rslt == BME68X_OK) + { + if (conf->enable == BME68X_ENABLE) + { + hctrl = BME68X_ENABLE_HEATER; + if (dev->variant_id == BME68X_VARIANT_GAS_HIGH) + { + run_gas = BME68X_ENABLE_GAS_MEAS_H; + } + else + { + run_gas = BME68X_ENABLE_GAS_MEAS_L; + } + } + else + { + hctrl = BME68X_DISABLE_HEATER; + run_gas = BME68X_DISABLE_GAS_MEAS; + } + + ctrl_gas_data[0] = BME68X_SET_BITS(ctrl_gas_data[0], BME68X_HCTRL, hctrl); + ctrl_gas_data[1] = BME68X_SET_BITS_POS_0(ctrl_gas_data[1], BME68X_NBCONV, nb_conv); + ctrl_gas_data[1] = BME68X_SET_BITS(ctrl_gas_data[1], BME68X_RUN_GAS, run_gas); + rslt = bme68x_set_regs(ctrl_gas_addr, ctrl_gas_data, 2, dev); + } + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* + * @brief This API is used to get the gas configuration of the sensor. + */ +int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t data_array[10] = { 0 }; + uint8_t i; + + /* FIXME: Add conversion to deg C and ms and add the other parameters */ + rslt = bme68x_get_regs(BME68X_REG_RES_HEAT0, data_array, 10, dev); + if (rslt == BME68X_OK) + { + if (conf && conf->heatr_dur_prof && conf->heatr_temp_prof) + { + for (i = 0; i < 10; i++) + { + conf->heatr_temp_prof[i] = data_array[i]; + } + + rslt = bme68x_get_regs(BME68X_REG_GAS_WAIT0, data_array, 10, dev); + if (rslt == BME68X_OK) + { + for (i = 0; i < 10; i++) + { + conf->heatr_dur_prof[i] = data_array[i]; + } + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + } + + return rslt; +} + +/* + * @brief This API performs Self-test of low and high gas variants of BME68X + */ +int8_t bme68x_selftest_check(const struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t n_fields; + uint8_t i = 0; + struct bme68x_data data[BME68X_N_MEAS] = { { 0 } }; + struct bme68x_dev t_dev; + struct bme68x_conf conf; + struct bme68x_heatr_conf heatr_conf; + + /* Copy required parameters from reference bme68x_dev struct */ + t_dev.amb_temp = 25; + t_dev.read = dev->read; + t_dev.write = dev->write; + t_dev.intf = dev->intf; + t_dev.delay_us = dev->delay_us; + t_dev.intf_ptr = dev->intf_ptr; + rslt = bme68x_init(&t_dev); + if (rslt == BME68X_OK) + { + /* Set the temperature, pressure and humidity & filter settings */ + conf.os_hum = BME68X_OS_1X; + conf.os_pres = BME68X_OS_16X; + conf.os_temp = BME68X_OS_2X; + + /* Set the remaining gas sensor settings and link the heating profile */ + heatr_conf.enable = BME68X_ENABLE; + heatr_conf.heatr_dur = BME68X_HEATR_DUR1; + heatr_conf.heatr_temp = BME68X_HIGH_TEMP; + rslt = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &heatr_conf, &t_dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_set_conf(&conf, &t_dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_set_op_mode(BME68X_FORCED_MODE, &t_dev); /* Trigger a measurement */ + if (rslt == BME68X_OK) + { + /* Wait for the measurement to complete */ + t_dev.delay_us(BME68X_HEATR_DUR1_DELAY, t_dev.intf_ptr); + rslt = bme68x_get_data(BME68X_FORCED_MODE, &data[0], &n_fields, &t_dev); + if (rslt == BME68X_OK) + { + if ((data[0].idac != 0x00) && (data[0].idac != 0xFF) && + (data[0].status & BME68X_GASM_VALID_MSK)) + { + rslt = BME68X_OK; + } + else + { + rslt = BME68X_E_SELF_TEST; + } + } + } + } + } + + heatr_conf.heatr_dur = BME68X_HEATR_DUR2; + while ((rslt == BME68X_OK) && (i < BME68X_N_MEAS)) + { + if (i % 2 == 0) + { + heatr_conf.heatr_temp = BME68X_HIGH_TEMP; /* Higher temperature */ + } + else + { + heatr_conf.heatr_temp = BME68X_LOW_TEMP; /* Lower temperature */ + } + + rslt = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &heatr_conf, &t_dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_set_conf(&conf, &t_dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_set_op_mode(BME68X_FORCED_MODE, &t_dev); /* Trigger a measurement */ + if (rslt == BME68X_OK) + { + /* Wait for the measurement to complete */ + t_dev.delay_us(BME68X_HEATR_DUR2_DELAY, t_dev.intf_ptr); + rslt = bme68x_get_data(BME68X_FORCED_MODE, &data[i], &n_fields, &t_dev); + } + } + } + + i++; + } + + if (rslt == BME68X_OK) + { + rslt = analyze_sensor_data(data, BME68X_N_MEAS); + } + } + + return rslt; +} + +/*****************************INTERNAL APIs***********************************************/ +#ifndef BME68X_USE_FPU + +/* @brief This internal API is used to calculate the temperature value. */ +static int16_t calc_temperature(uint32_t temp_adc, struct bme68x_dev *dev) +{ + int64_t var1; + int64_t var2; + int64_t var3; + int16_t calc_temp; + + /*lint -save -e701 -e702 -e704 */ + var1 = ((int32_t)temp_adc >> 3) - ((int32_t)dev->calib.par_t1 << 1); + var2 = (var1 * (int32_t)dev->calib.par_t2) >> 11; + var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; + var3 = ((var3) * ((int32_t)dev->calib.par_t3 << 4)) >> 14; + dev->calib.t_fine = (int32_t)(var2 + var3); + calc_temp = (int16_t)(((dev->calib.t_fine * 5) + 128) >> 8); + + /*lint -restore */ + return calc_temp; +} + +/* @brief This internal API is used to calculate the pressure value. */ +static uint32_t calc_pressure(uint32_t pres_adc, const struct bme68x_dev *dev) +{ + int32_t var1; + int32_t var2; + int32_t var3; + int32_t pressure_comp; + + /* This value is used to check precedence to multiplication or division + * in the pressure compensation equation to achieve least loss of precision and + * avoiding overflows. + * i.e Comparing value, pres_ovf_check = (1 << 31) >> 1 + */ + const int32_t pres_ovf_check = INT32_C(0x40000000); + + /*lint -save -e701 -e702 -e713 */ + var1 = (((int32_t)dev->calib.t_fine) >> 1) - 64000; + var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * (int32_t)dev->calib.par_p6) >> 2; + var2 = var2 + ((var1 * (int32_t)dev->calib.par_p5) << 1); + var2 = (var2 >> 2) + ((int32_t)dev->calib.par_p4 << 16); + var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * ((int32_t)dev->calib.par_p3 << 5)) >> 3) + + (((int32_t)dev->calib.par_p2 * var1) >> 1); + var1 = var1 >> 18; + var1 = ((32768 + var1) * (int32_t)dev->calib.par_p1) >> 15; + pressure_comp = 1048576 - pres_adc; + pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125)); + if (pressure_comp >= pres_ovf_check) + { + pressure_comp = ((pressure_comp / var1) << 1); + } + else + { + pressure_comp = ((pressure_comp << 1) / var1); + } + + var1 = ((int32_t)dev->calib.par_p9 * (int32_t)(((pressure_comp >> 3) * (pressure_comp >> 3)) >> 13)) >> 12; + var2 = ((int32_t)(pressure_comp >> 2) * (int32_t)dev->calib.par_p8) >> 13; + var3 = + ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * + (int32_t)dev->calib.par_p10) >> 17; + pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 + ((int32_t)dev->calib.par_p7 << 7)) >> 4); + + /*lint -restore */ + return (uint32_t)pressure_comp; +} + +/* This internal API is used to calculate the humidity in integer */ +static uint32_t calc_humidity(uint16_t hum_adc, const struct bme68x_dev *dev) +{ + int32_t var1; + int32_t var2; + int32_t var3; + int32_t var4; + int32_t var5; + int32_t var6; + int32_t temp_scaled; + int32_t calc_hum; + + /*lint -save -e702 -e704 */ + temp_scaled = (((int32_t)dev->calib.t_fine * 5) + 128) >> 8; + var1 = (int32_t)(hum_adc - ((int32_t)((int32_t)dev->calib.par_h1 * 16))) - + (((temp_scaled * (int32_t)dev->calib.par_h3) / ((int32_t)100)) >> 1); + var2 = + ((int32_t)dev->calib.par_h2 * + (((temp_scaled * (int32_t)dev->calib.par_h4) / ((int32_t)100)) + + (((temp_scaled * ((temp_scaled * (int32_t)dev->calib.par_h5) / ((int32_t)100))) >> 6) / ((int32_t)100)) + + (int32_t)(1 << 14))) >> 10; + var3 = var1 * var2; + var4 = (int32_t)dev->calib.par_h6 << 7; + var4 = ((var4) + ((temp_scaled * (int32_t)dev->calib.par_h7) / ((int32_t)100))) >> 4; + var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; + var6 = (var4 * var5) >> 1; + calc_hum = (((var3 + var6) >> 10) * ((int32_t)1000)) >> 12; + if (calc_hum > 100000) /* Cap at 100%rH */ + { + calc_hum = 100000; + } + else if (calc_hum < 0) + { + calc_hum = 0; + } + + /*lint -restore */ + return (uint32_t)calc_hum; +} + +/* This internal API is used to calculate the gas resistance low */ +static uint32_t calc_gas_resistance_low(uint16_t gas_res_adc, uint8_t gas_range, const struct bme68x_dev *dev) +{ + int64_t var1; + uint64_t var2; + int64_t var3; + uint32_t calc_gas_res; + uint32_t lookup_table1[16] = { + UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), + UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), UINT32_C(2147483647), UINT32_C(2147483647), + UINT32_C(2143188679), UINT32_C(2136746228), UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), + UINT32_C(2147483647) + }; + uint32_t lookup_table2[16] = { + UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), UINT32_C(255744255), + UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), UINT32_C(8000000), UINT32_C( + 4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), UINT32_C(250000), UINT32_C(125000) + }; + + /*lint -save -e704 */ + var1 = (int64_t)((1340 + (5 * (int64_t)dev->calib.range_sw_err)) * ((int64_t)lookup_table1[gas_range])) >> 16; + var2 = (((int64_t)((int64_t)gas_res_adc << 15) - (int64_t)(16777216)) + var1); + var3 = (((int64_t)lookup_table2[gas_range] * (int64_t)var1) >> 9); + calc_gas_res = (uint32_t)((var3 + ((int64_t)var2 >> 1)) / (int64_t)var2); + + /*lint -restore */ + return calc_gas_res; +} + +/* This internal API is used to calculate the gas resistance */ +static uint32_t calc_gas_resistance_high(uint16_t gas_res_adc, uint8_t gas_range) +{ + uint32_t calc_gas_res; + uint32_t var1 = UINT32_C(262144) >> gas_range; + int32_t var2 = (int32_t)gas_res_adc - INT32_C(512); + + var2 *= INT32_C(3); + var2 = INT32_C(4096) + var2; + + /* multiplying 10000 then dividing then multiplying by 100 instead of multiplying by 1000000 to prevent overflow */ + calc_gas_res = (UINT32_C(10000) * var1) / (uint32_t)var2; + calc_gas_res = calc_gas_res * 100; + + return calc_gas_res; +} + +/* This internal API is used to calculate the heater resistance value using float */ +static uint8_t calc_res_heat(uint16_t temp, const struct bme68x_dev *dev) +{ + uint8_t heatr_res; + int32_t var1; + int32_t var2; + int32_t var3; + int32_t var4; + int32_t var5; + int32_t heatr_res_x100; + + if (temp > 400) /* Cap temperature */ + { + temp = 400; + } + + var1 = (((int32_t)dev->amb_temp * dev->calib.par_gh3) / 1000) * 256; + var2 = (dev->calib.par_gh1 + 784) * (((((dev->calib.par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); + var3 = var1 + (var2 / 2); + var4 = (var3 / (dev->calib.res_heat_range + 4)); + var5 = (131 * dev->calib.res_heat_val) + 65536; + heatr_res_x100 = (int32_t)(((var4 / var5) - 250) * 34); + heatr_res = (uint8_t)((heatr_res_x100 + 50) / 100); + + return heatr_res; +} + +#else + +/* @brief This internal API is used to calculate the temperature value. */ +static float calc_temperature(uint32_t temp_adc, struct bme68x_dev *dev) +{ + float var1; + float var2; + float calc_temp; + + /* calculate var1 data */ + var1 = ((((float)temp_adc / 16384.0f) - ((float)dev->calib.par_t1 / 1024.0f)) * ((float)dev->calib.par_t2)); + + /* calculate var2 data */ + var2 = + (((((float)temp_adc / 131072.0f) - ((float)dev->calib.par_t1 / 8192.0f)) * + (((float)temp_adc / 131072.0f) - ((float)dev->calib.par_t1 / 8192.0f))) * ((float)dev->calib.par_t3 * 16.0f)); + + /* t_fine value*/ + dev->calib.t_fine = (var1 + var2); + + /* compensated temperature data*/ + calc_temp = ((dev->calib.t_fine) / 5120.0f); + + return calc_temp; +} + +/* @brief This internal API is used to calculate the pressure value. */ +static float calc_pressure(uint32_t pres_adc, const struct bme68x_dev *dev) +{ + float var1; + float var2; + float var3; + float calc_pres; + + var1 = (((float)dev->calib.t_fine / 2.0f) - 64000.0f); + var2 = var1 * var1 * (((float)dev->calib.par_p6) / (131072.0f)); + var2 = var2 + (var1 * ((float)dev->calib.par_p5) * 2.0f); + var2 = (var2 / 4.0f) + (((float)dev->calib.par_p4) * 65536.0f); + var1 = (((((float)dev->calib.par_p3 * var1 * var1) / 16384.0f) + ((float)dev->calib.par_p2 * var1)) / 524288.0f); + var1 = ((1.0f + (var1 / 32768.0f)) * ((float)dev->calib.par_p1)); + calc_pres = (1048576.0f - ((float)pres_adc)); + + /* Avoid exception caused by division by zero */ + if ((int)var1 != 0) + { + calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); + var1 = (((float)dev->calib.par_p9) * calc_pres * calc_pres) / 2147483648.0f; + var2 = calc_pres * (((float)dev->calib.par_p8) / 32768.0f); + var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) * (dev->calib.par_p10 / 131072.0f)); + calc_pres = (calc_pres + (var1 + var2 + var3 + ((float)dev->calib.par_p7 * 128.0f)) / 16.0f); + } + else + { + calc_pres = 0; + } + + return calc_pres; +} + +/* This internal API is used to calculate the humidity in integer */ +static float calc_humidity(uint16_t hum_adc, const struct bme68x_dev *dev) +{ + float calc_hum; + float var1; + float var2; + float var3; + float var4; + float temp_comp; + + /* compensated temperature data*/ + temp_comp = ((dev->calib.t_fine) / 5120.0f); + var1 = (float)((float)hum_adc) - + (((float)dev->calib.par_h1 * 16.0f) + (((float)dev->calib.par_h3 / 2.0f) * temp_comp)); + var2 = var1 * + ((float)(((float)dev->calib.par_h2 / 262144.0f) * + (1.0f + (((float)dev->calib.par_h4 / 16384.0f) * temp_comp) + + (((float)dev->calib.par_h5 / 1048576.0f) * temp_comp * temp_comp)))); + var3 = (float)dev->calib.par_h6 / 16384.0f; + var4 = (float)dev->calib.par_h7 / 2097152.0f; + calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); + if (calc_hum > 100.0f) + { + calc_hum = 100.0f; + } + else if (calc_hum < 0.0f) + { + calc_hum = 0.0f; + } + + return calc_hum; +} + +/* This internal API is used to calculate the gas resistance low value in float */ +static float calc_gas_resistance_low(uint16_t gas_res_adc, uint8_t gas_range, const struct bme68x_dev *dev) +{ + float calc_gas_res; + float var1; + float var2; + float var3; + float gas_res_f = gas_res_adc; + float gas_range_f = (1U << gas_range); /*lint !e790 / Suspicious truncation, integral to float */ + const float lookup_k1_range[16] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, -0.8f, 0.0f, 0.0f, -0.2f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f + }; + const float lookup_k2_range[16] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.7f, 0.0f, -0.8f, -0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f + }; + + var1 = (1340.0f + (5.0f * dev->calib.range_sw_err)); + var2 = (var1) * (1.0f + lookup_k1_range[gas_range] / 100.0f); + var3 = 1.0f + (lookup_k2_range[gas_range] / 100.0f); + calc_gas_res = 1.0f / (float)(var3 * (0.000000125f) * gas_range_f * (((gas_res_f - 512.0f) / var2) + 1.0f)); + + return calc_gas_res; +} + +/* This internal API is used to calculate the gas resistance value in float */ +static float calc_gas_resistance_high(uint16_t gas_res_adc, uint8_t gas_range) +{ + float calc_gas_res; + uint32_t var1 = UINT32_C(262144) >> gas_range; + int32_t var2 = (int32_t)gas_res_adc - INT32_C(512); + + var2 *= INT32_C(3); + var2 = INT32_C(4096) + var2; + + calc_gas_res = 1000000.0f * (float)var1 / (float)var2; + + return calc_gas_res; +} + +/* This internal API is used to calculate the heater resistance value */ +static uint8_t calc_res_heat(uint16_t temp, const struct bme68x_dev *dev) +{ + float var1; + float var2; + float var3; + float var4; + float var5; + uint8_t res_heat; + + if (temp > 400) /* Cap temperature */ + { + temp = 400; + } + + var1 = (((float)dev->calib.par_gh1 / (16.0f)) + 49.0f); + var2 = ((((float)dev->calib.par_gh2 / (32768.0f)) * (0.0005f)) + 0.00235f); + var3 = ((float)dev->calib.par_gh3 / (1024.0f)); + var4 = (var1 * (1.0f + (var2 * (float)temp))); + var5 = (var4 + (var3 * (float)dev->amb_temp)); + res_heat = + (uint8_t)(3.4f * + ((var5 * (4 / (4 + (float)dev->calib.res_heat_range)) * + (1 / (1 + ((float)dev->calib.res_heat_val * 0.002f)))) - + 25)); + + return res_heat; +} + +#endif + +/* This internal API is used to calculate the gas wait */ +static uint8_t calc_gas_wait(uint16_t dur) +{ + uint8_t factor = 0; + uint8_t durval; + + if (dur >= 0xfc0) + { + durval = 0xff; /* Max duration*/ + } + else + { + while (dur > 0x3F) + { + dur = dur / 4; + factor += 1; + } + + durval = (uint8_t)(dur + (factor * 64)); + } + + return durval; +} + +/* This internal API is used to read a single data of the sensor */ +static int8_t read_field_data(uint8_t index, struct bme68x_data *data, struct bme68x_dev *dev) +{ + int8_t rslt = BME68X_OK; + uint8_t buff[BME68X_LEN_FIELD] = { 0 }; + uint8_t gas_range_l, gas_range_h; + uint32_t adc_temp; + uint32_t adc_pres; + uint16_t adc_hum; + uint16_t adc_gas_res_low, adc_gas_res_high; + uint8_t tries = 5; + + while ((tries) && (rslt == BME68X_OK)) + { + rslt = bme68x_get_regs(((uint8_t)(BME68X_REG_FIELD0 + (index * BME68X_LEN_FIELD_OFFSET))), + buff, + (uint16_t)BME68X_LEN_FIELD, + dev); + if (!data) + { + rslt = BME68X_E_NULL_PTR; + break; + } + + data->status = buff[0] & BME68X_NEW_DATA_MSK; + data->gas_index = buff[0] & BME68X_GAS_INDEX_MSK; + data->meas_index = buff[1]; + + /* read the raw data from the sensor */ + adc_pres = (uint32_t)(((uint32_t)buff[2] * 4096) | ((uint32_t)buff[3] * 16) | ((uint32_t)buff[4] / 16)); + adc_temp = (uint32_t)(((uint32_t)buff[5] * 4096) | ((uint32_t)buff[6] * 16) | ((uint32_t)buff[7] / 16)); + adc_hum = (uint16_t)(((uint32_t)buff[8] * 256) | (uint32_t)buff[9]); + adc_gas_res_low = (uint16_t)((uint32_t)buff[13] * 4 | (((uint32_t)buff[14]) / 64)); + adc_gas_res_high = (uint16_t)((uint32_t)buff[15] * 4 | (((uint32_t)buff[16]) / 64)); + gas_range_l = buff[14] & BME68X_GAS_RANGE_MSK; + gas_range_h = buff[16] & BME68X_GAS_RANGE_MSK; + if (dev->variant_id == BME68X_VARIANT_GAS_HIGH) + { + data->status |= buff[16] & BME68X_GASM_VALID_MSK; + data->status |= buff[16] & BME68X_HEAT_STAB_MSK; + } + else + { + data->status |= buff[14] & BME68X_GASM_VALID_MSK; + data->status |= buff[14] & BME68X_HEAT_STAB_MSK; + } + + if ((data->status & BME68X_NEW_DATA_MSK) && (rslt == BME68X_OK)) + { + rslt = bme68x_get_regs(BME68X_REG_RES_HEAT0 + data->gas_index, &data->res_heat, 1, dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_IDAC_HEAT0 + data->gas_index, &data->idac, 1, dev); + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_GAS_WAIT0 + data->gas_index, &data->gas_wait, 1, dev); + } + + if (rslt == BME68X_OK) + { + data->temperature = calc_temperature(adc_temp, dev); + data->pressure = calc_pressure(adc_pres, dev); + data->humidity = calc_humidity(adc_hum, dev); + if (dev->variant_id == BME68X_VARIANT_GAS_HIGH) + { + data->gas_resistance = calc_gas_resistance_high(adc_gas_res_high, gas_range_h); + } + else + { + data->gas_resistance = calc_gas_resistance_low(adc_gas_res_low, gas_range_l, dev); + } + + break; + } + } + + if (rslt == BME68X_OK) + { + dev->delay_us(BME68X_PERIOD_POLL, dev->intf_ptr); + } + + tries--; + } + + return rslt; +} + +/* This internal API is used to read all data fields of the sensor */ +static int8_t read_all_field_data(struct bme68x_data * const data[], struct bme68x_dev *dev) +{ + int8_t rslt = BME68X_OK; + uint8_t buff[BME68X_LEN_FIELD * 3] = { 0 }; + uint8_t gas_range_l, gas_range_h; + uint32_t adc_temp; + uint32_t adc_pres; + uint16_t adc_hum; + uint16_t adc_gas_res_low, adc_gas_res_high; + uint8_t off; + uint8_t set_val[30] = { 0 }; /* idac, res_heat, gas_wait */ + uint8_t i; + + if (!data[0] && !data[1] && !data[2]) + { + rslt = BME68X_E_NULL_PTR; + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_FIELD0, buff, (uint32_t) BME68X_LEN_FIELD * 3, dev); + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_IDAC_HEAT0, set_val, 30, dev); + } + + for (i = 0; ((i < 3) && (rslt == BME68X_OK)); i++) + { + off = (uint8_t)(i * BME68X_LEN_FIELD); + data[i]->status = buff[off] & BME68X_NEW_DATA_MSK; + data[i]->gas_index = buff[off] & BME68X_GAS_INDEX_MSK; + data[i]->meas_index = buff[off + 1]; + + /* read the raw data from the sensor */ + adc_pres = + (uint32_t) (((uint32_t) buff[off + 2] * 4096) | ((uint32_t) buff[off + 3] * 16) | + ((uint32_t) buff[off + 4] / 16)); + adc_temp = + (uint32_t) (((uint32_t) buff[off + 5] * 4096) | ((uint32_t) buff[off + 6] * 16) | + ((uint32_t) buff[off + 7] / 16)); + adc_hum = (uint16_t) (((uint32_t) buff[off + 8] * 256) | (uint32_t) buff[off + 9]); + adc_gas_res_low = (uint16_t) ((uint32_t) buff[off + 13] * 4 | (((uint32_t) buff[off + 14]) / 64)); + adc_gas_res_high = (uint16_t) ((uint32_t) buff[off + 15] * 4 | (((uint32_t) buff[off + 16]) / 64)); + gas_range_l = buff[off + 14] & BME68X_GAS_RANGE_MSK; + gas_range_h = buff[off + 16] & BME68X_GAS_RANGE_MSK; + if (dev->variant_id == BME68X_VARIANT_GAS_HIGH) + { + data[i]->status |= buff[off + 16] & BME68X_GASM_VALID_MSK; + data[i]->status |= buff[off + 16] & BME68X_HEAT_STAB_MSK; + } + else + { + data[i]->status |= buff[off + 14] & BME68X_GASM_VALID_MSK; + data[i]->status |= buff[off + 14] & BME68X_HEAT_STAB_MSK; + } + + data[i]->idac = set_val[data[i]->gas_index]; + data[i]->res_heat = set_val[10 + data[i]->gas_index]; + data[i]->gas_wait = set_val[20 + data[i]->gas_index]; + data[i]->temperature = calc_temperature(adc_temp, dev); + data[i]->pressure = calc_pressure(adc_pres, dev); + data[i]->humidity = calc_humidity(adc_hum, dev); + if (dev->variant_id == BME68X_VARIANT_GAS_HIGH) + { + data[i]->gas_resistance = calc_gas_resistance_high(adc_gas_res_high, gas_range_h); + } + else + { + data[i]->gas_resistance = calc_gas_resistance_low(adc_gas_res_low, gas_range_l, dev); + } + } + + return rslt; +} + +/* This internal API is used to switch between SPI memory pages */ +static int8_t set_mem_page(uint8_t reg_addr, struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t reg; + uint8_t mem_page; + + /* Check for null pointers in the device structure*/ + rslt = null_ptr_check(dev); + if (rslt == BME68X_OK) + { + if (reg_addr > 0x7f) + { + mem_page = BME68X_MEM_PAGE1; + } + else + { + mem_page = BME68X_MEM_PAGE0; + } + + if (mem_page != dev->mem_page) + { + dev->mem_page = mem_page; + dev->intf_rslt = dev->read(BME68X_REG_MEM_PAGE | BME68X_SPI_RD_MSK, ®, 1, dev->intf_ptr); + if (dev->intf_rslt != 0) + { + rslt = BME68X_E_COM_FAIL; + } + + if (rslt == BME68X_OK) + { + reg = reg & (~BME68X_MEM_PAGE_MSK); + reg = reg | (dev->mem_page & BME68X_MEM_PAGE_MSK); + dev->intf_rslt = dev->write(BME68X_REG_MEM_PAGE & BME68X_SPI_WR_MSK, ®, 1, dev->intf_ptr); + if (dev->intf_rslt != 0) + { + rslt = BME68X_E_COM_FAIL; + } + } + } + } + + return rslt; +} + +/* This internal API is used to get the current SPI memory page */ +static int8_t get_mem_page(struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t reg; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + if (rslt == BME68X_OK) + { + dev->intf_rslt = dev->read(BME68X_REG_MEM_PAGE | BME68X_SPI_RD_MSK, ®, 1, dev->intf_ptr); + if (dev->intf_rslt != 0) + { + rslt = BME68X_E_COM_FAIL; + } + else + { + dev->mem_page = reg & BME68X_MEM_PAGE_MSK; + } + } + + return rslt; +} + +/* This internal API is used to limit the max value of a parameter */ +static int8_t boundary_check(uint8_t *value, uint8_t max, struct bme68x_dev *dev) +{ + int8_t rslt; + + rslt = null_ptr_check(dev); + if ((value != NULL) && (rslt == BME68X_OK)) + { + /* Check if value is above maximum value */ + if (*value > max) + { + /* Auto correct the invalid value to maximum value */ + *value = max; + dev->info_msg |= BME68X_I_PARAM_CORR; + } + } + else + { + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* This internal API is used to check the bme68x_dev for null pointers */ +static int8_t null_ptr_check(const struct bme68x_dev *dev) +{ + int8_t rslt = BME68X_OK; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL)) + { + /* Device structure pointer is not valid */ + rslt = BME68X_E_NULL_PTR; + } + + return rslt; +} + +/* This internal API is used to set heater configurations */ +static int8_t set_conf(const struct bme68x_heatr_conf *conf, uint8_t op_mode, uint8_t *nb_conv, struct bme68x_dev *dev) +{ + int8_t rslt = BME68X_OK; + uint8_t i; + uint8_t shared_dur; + uint8_t write_len = 0; + uint8_t heater_dur_shared_addr = BME68X_REG_SHD_HEATR_DUR; + uint8_t rh_reg_addr[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t rh_reg_data[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t gw_reg_addr[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t gw_reg_data[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + switch (op_mode) + { + case BME68X_FORCED_MODE: + rh_reg_addr[0] = BME68X_REG_RES_HEAT0; + rh_reg_data[0] = calc_res_heat(conf->heatr_temp, dev); + gw_reg_addr[0] = BME68X_REG_GAS_WAIT0; + gw_reg_data[0] = calc_gas_wait(conf->heatr_dur); + (*nb_conv) = 0; + write_len = 1; + break; + case BME68X_SEQUENTIAL_MODE: + if ((!conf->heatr_dur_prof) || (!conf->heatr_temp_prof)) + { + rslt = BME68X_E_NULL_PTR; + break; + } + + for (i = 0; i < conf->profile_len; i++) + { + rh_reg_addr[i] = BME68X_REG_RES_HEAT0 + i; + rh_reg_data[i] = calc_res_heat(conf->heatr_temp_prof[i], dev); + gw_reg_addr[i] = BME68X_REG_GAS_WAIT0 + i; + gw_reg_data[i] = calc_gas_wait(conf->heatr_dur_prof[i]); + } + + (*nb_conv) = conf->profile_len; + write_len = conf->profile_len; + break; + case BME68X_PARALLEL_MODE: + if ((!conf->heatr_dur_prof) || (!conf->heatr_temp_prof)) + { + rslt = BME68X_E_NULL_PTR; + break; + } + + if (conf->shared_heatr_dur == 0) + { + rslt = BME68X_W_DEFINE_SHD_HEATR_DUR; + } + + for (i = 0; i < conf->profile_len; i++) + { + rh_reg_addr[i] = BME68X_REG_RES_HEAT0 + i; + rh_reg_data[i] = calc_res_heat(conf->heatr_temp_prof[i], dev); + gw_reg_addr[i] = BME68X_REG_GAS_WAIT0 + i; + gw_reg_data[i] = (uint8_t) conf->heatr_dur_prof[i]; + } + + (*nb_conv) = conf->profile_len; + write_len = conf->profile_len; + shared_dur = calc_heatr_dur_shared(conf->shared_heatr_dur); + if (rslt == BME68X_OK) + { + rslt = bme68x_set_regs(&heater_dur_shared_addr, &shared_dur, 1, dev); + } + + break; + default: + rslt = BME68X_W_DEFINE_OP_MODE; + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_set_regs(rh_reg_addr, rh_reg_data, write_len, dev); + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_set_regs(gw_reg_addr, gw_reg_data, write_len, dev); + } + + return rslt; +} + +/* This internal API is used to calculate the register value for + * shared heater duration */ +static uint8_t calc_heatr_dur_shared(uint16_t dur) +{ + uint8_t factor = 0; + uint8_t heatdurval; + + if (dur >= 0x783) + { + heatdurval = 0xff; /* Max duration */ + } + else + { + /* Step size of 0.477ms */ + dur = (uint16_t)(((uint32_t)dur * 1000) / 477); + while (dur > 0x3F) + { + dur = dur >> 2; + factor += 1; + } + + heatdurval = (uint8_t)(dur + (factor * 64)); + } + + return heatdurval; +} + +/* This internal API is used sort the sensor data */ +static void sort_sensor_data(uint8_t low_index, uint8_t high_index, struct bme68x_data *field[]) +{ + int16_t meas_index1; + int16_t meas_index2; + + meas_index1 = (int16_t)field[low_index]->meas_index; + meas_index2 = (int16_t)field[high_index]->meas_index; + if ((field[low_index]->status & BME68X_NEW_DATA_MSK) && (field[high_index]->status & BME68X_NEW_DATA_MSK)) + { + int16_t diff = meas_index2 - meas_index1; + if (((diff > -3) && (diff < 0)) || (diff > 2)) + { + swap_fields(low_index, high_index, field); + } + } + else if (field[high_index]->status & BME68X_NEW_DATA_MSK) + { + swap_fields(low_index, high_index, field); + } + + /* Sorting field data + * + * The 3 fields are filled in a fixed order with data in an incrementing + * 8-bit sub-measurement index which looks like + * Field index | Sub-meas index + * 0 | 0 + * 1 | 1 + * 2 | 2 + * 0 | 3 + * 1 | 4 + * 2 | 5 + * ... + * 0 | 252 + * 1 | 253 + * 2 | 254 + * 0 | 255 + * 1 | 0 + * 2 | 1 + * + * The fields are sorted in a way so as to always deal with only a snapshot + * of comparing 2 fields at a time. The order being + * field0 & field1 + * field0 & field2 + * field1 & field2 + * Here the oldest data should be in field0 while the newest is in field2. + * In the following documentation, field0's position would referred to as + * the lowest and field2 as the highest. + * + * In order to sort we have to consider the following cases, + * + * Case A: No fields have new data + * Then do not sort, as this data has already been read. + * + * Case B: Higher field has new data + * Then the new field get's the lowest position. + * + * Case C: Both fields have new data + * We have to put the oldest sample in the lowest position. Since the + * sub-meas index contains in essence the age of the sample, we calculate + * the difference between the higher field and the lower field. + * Here we have 3 sub-cases, + * Case 1: Regular read without overwrite + * Field index | Sub-meas index + * 0 | 3 + * 1 | 4 + * + * Field index | Sub-meas index + * 0 | 3 + * 2 | 5 + * + * The difference is always <= 2. There is no need to swap as the + * oldest sample is already in the lowest position. + * + * Case 2: Regular read with an overflow and without an overwrite + * Field index | Sub-meas index + * 0 | 255 + * 1 | 0 + * + * Field index | Sub-meas index + * 0 | 254 + * 2 | 0 + * + * The difference is always <= -3. There is no need to swap as the + * oldest sample is already in the lowest position. + * + * Case 3: Regular read with overwrite + * Field index | Sub-meas index + * 0 | 6 + * 1 | 4 + * + * Field index | Sub-meas index + * 0 | 6 + * 2 | 5 + * + * The difference is always > -3. There is a need to swap as the + * oldest sample is not in the lowest position. + * + * Case 4: Regular read with overwrite and overflow + * Field index | Sub-meas index + * 0 | 0 + * 1 | 254 + * + * Field index | Sub-meas index + * 0 | 0 + * 2 | 255 + * + * The difference is always > 2. There is a need to swap as the + * oldest sample is not in the lowest position. + * + * To summarize, we have to swap when + * - The higher field has new data and the lower field does not. + * - If both fields have new data, then the difference of sub-meas index + * between the higher field and the lower field creates the + * following condition for swapping. + * - (diff > -3) && (diff < 0), combination of cases 1, 2, and 3. + * - diff > 2, case 4. + * + * Here the limits of -3 and 2 derive from the fact that there are 3 fields. + * These values decrease or increase respectively if the number of fields increases. + */ +} + +/* This internal API is used sort the sensor data */ +static void swap_fields(uint8_t index1, uint8_t index2, struct bme68x_data *field[]) +{ + struct bme68x_data *temp; + + temp = field[index1]; + field[index1] = field[index2]; + field[index2] = temp; +} + +/* This Function is to analyze the sensor data */ +static int8_t analyze_sensor_data(const struct bme68x_data *data, uint8_t n_meas) +{ + int8_t rslt = BME68X_OK; + uint8_t self_test_failed = 0, i; + uint32_t cent_res = 0; + + if ((data[0].temperature < BME68X_MIN_TEMPERATURE) || (data[0].temperature > BME68X_MAX_TEMPERATURE)) + { + self_test_failed++; + } + + if ((data[0].pressure < BME68X_MIN_PRESSURE) || (data[0].pressure > BME68X_MAX_PRESSURE)) + { + self_test_failed++; + } + + if ((data[0].humidity < BME68X_MIN_HUMIDITY) || (data[0].humidity > BME68X_MAX_HUMIDITY)) + { + self_test_failed++; + } + + for (i = 0; i < n_meas; i++) /* Every gas measurement should be valid */ + { + if (!(data[i].status & BME68X_GASM_VALID_MSK)) + { + self_test_failed++; + } + } + + if (n_meas >= 6) + { + cent_res = (uint32_t)((5 * (data[3].gas_resistance + data[5].gas_resistance)) / (2 * data[4].gas_resistance)); + } + + if (cent_res < 6) + { + self_test_failed++; + } + + if (self_test_failed) + { + rslt = BME68X_E_SELF_TEST; + } + + return rslt; +} + +/* This internal API is used to read the calibration coefficients */ +static int8_t get_calib_data(struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t coeff_array[BME68X_LEN_COEFF_ALL]; + + rslt = bme68x_get_regs(BME68X_REG_COEFF1, coeff_array, BME68X_LEN_COEFF1, dev); + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_COEFF2, &coeff_array[BME68X_LEN_COEFF1], BME68X_LEN_COEFF2, dev); + } + + if (rslt == BME68X_OK) + { + rslt = bme68x_get_regs(BME68X_REG_COEFF3, + &coeff_array[BME68X_LEN_COEFF1 + BME68X_LEN_COEFF2], + BME68X_LEN_COEFF3, + dev); + } + + if (rslt == BME68X_OK) + { + /* Temperature related coefficients */ + dev->calib.par_t1 = + (uint16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_T1_MSB], coeff_array[BME68X_IDX_T1_LSB])); + dev->calib.par_t2 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_T2_MSB], coeff_array[BME68X_IDX_T2_LSB])); + dev->calib.par_t3 = (int8_t)(coeff_array[BME68X_IDX_T3]); + + /* Pressure related coefficients */ + dev->calib.par_p1 = + (uint16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P1_MSB], coeff_array[BME68X_IDX_P1_LSB])); + dev->calib.par_p2 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P2_MSB], coeff_array[BME68X_IDX_P2_LSB])); + dev->calib.par_p3 = (int8_t)coeff_array[BME68X_IDX_P3]; + dev->calib.par_p4 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P4_MSB], coeff_array[BME68X_IDX_P4_LSB])); + dev->calib.par_p5 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P5_MSB], coeff_array[BME68X_IDX_P5_LSB])); + dev->calib.par_p6 = (int8_t)(coeff_array[BME68X_IDX_P6]); + dev->calib.par_p7 = (int8_t)(coeff_array[BME68X_IDX_P7]); + dev->calib.par_p8 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P8_MSB], coeff_array[BME68X_IDX_P8_LSB])); + dev->calib.par_p9 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_P9_MSB], coeff_array[BME68X_IDX_P9_LSB])); + dev->calib.par_p10 = (uint8_t)(coeff_array[BME68X_IDX_P10]); + + /* Humidity related coefficients */ + dev->calib.par_h1 = + (uint16_t)(((uint16_t)coeff_array[BME68X_IDX_H1_MSB] << 4) | + (coeff_array[BME68X_IDX_H1_LSB] & BME68X_BIT_H1_DATA_MSK)); + dev->calib.par_h2 = + (uint16_t)(((uint16_t)coeff_array[BME68X_IDX_H2_MSB] << 4) | ((coeff_array[BME68X_IDX_H2_LSB]) >> 4)); + dev->calib.par_h3 = (int8_t)coeff_array[BME68X_IDX_H3]; + dev->calib.par_h4 = (int8_t)coeff_array[BME68X_IDX_H4]; + dev->calib.par_h5 = (int8_t)coeff_array[BME68X_IDX_H5]; + dev->calib.par_h6 = (uint8_t)coeff_array[BME68X_IDX_H6]; + dev->calib.par_h7 = (int8_t)coeff_array[BME68X_IDX_H7]; + + /* Gas heater related coefficients */ + dev->calib.par_gh1 = (int8_t)coeff_array[BME68X_IDX_GH1]; + dev->calib.par_gh2 = + (int16_t)(BME68X_CONCAT_BYTES(coeff_array[BME68X_IDX_GH2_MSB], coeff_array[BME68X_IDX_GH2_LSB])); + dev->calib.par_gh3 = (int8_t)coeff_array[BME68X_IDX_GH3]; + + /* Other coefficients */ + dev->calib.res_heat_range = ((coeff_array[BME68X_IDX_RES_HEAT_RANGE] & BME68X_RHRANGE_MSK) / 16); + dev->calib.res_heat_val = (int8_t)coeff_array[BME68X_IDX_RES_HEAT_VAL]; + dev->calib.range_sw_err = ((int8_t)(coeff_array[BME68X_IDX_RANGE_SW_ERR] & BME68X_RSERROR_MSK)) / 16; + } + + return rslt; +} + +/* This internal API is used to read variant ID information from the register */ +static int8_t read_variant_id(struct bme68x_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = 0; + + /* Read variant ID information register */ + rslt = bme68x_get_regs(BME68X_REG_VARIANT_ID, ®_data, 1, dev); + + if (rslt == BME68X_OK) + { + dev->variant_id = reg_data; + } + + return rslt; +} diff --git a/src/bme68x/bme68x.h b/src/bme68x/bme68x.h new file mode 100644 index 0000000..e6d4828 --- /dev/null +++ b/src/bme68x/bme68x.h @@ -0,0 +1,323 @@ +/** +* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bme68x.h +* @date 2021-11-09 +* @version v4.4.7 +* +*/ + +/*! + * @defgroup bme68x BME68X + * @brief Product Overview + * and Sensor API Source Code + */ + +#ifndef BME68X_H_ +#define BME68X_H_ + +#include "bme68x_defs.h" + +/* CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup bme68x + * \defgroup bme68xApiInit Initialization + * @brief Initialize the sensor and device structure + */ + +/*! + * \ingroup bme68xApiInit + * \page bme68x_api_bme68x_init bme68x_init + * \code + * int8_t bme68x_init(struct bme68x_dev *dev); + * \endcode + * @details This API reads the chip-id of the sensor which is the first step to + * verify the sensor and also calibrates the sensor + * As this API is the entry point, call this API before using other APIs. + * + * @param[in,out] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_init(struct bme68x_dev *dev); + +/** + * \ingroup bme68x + * \defgroup bme68xApiRegister Registers + * @brief Generic API for accessing sensor registers + */ + +/*! + * \ingroup bme68xApiRegister + * \page bme68x_api_bme68x_set_regs bme68x_set_regs + * \code + * int8_t bme68x_set_regs(const uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev) + * \endcode + * @details This API writes the given data to the register address of the sensor + * + * @param[in] reg_addr : Register addresses to where the data is to be written + * @param[in] reg_data : Pointer to data buffer which is to be written + * in the reg_addr of sensor. + * @param[in] len : No of bytes of data to write + * @param[in,out] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiRegister + * \page bme68x_api_bme68x_get_regs bme68x_get_regs + * \code + * int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev) + * \endcode + * @details This API reads the data from the given register address of sensor. + * + * @param[in] reg_addr : Register address from where the data to be read + * @param[out] reg_data : Pointer to data buffer to store the read data. + * @param[in] len : No of bytes of data to be read. + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bme68x_dev *dev); + +/** + * \ingroup bme68x + * \defgroup bme68xApiSystem System + * @brief API that performs system-level operations + */ + +/*! + * \ingroup bme68xApiSystem + * \page bme68x_api_bme68x_soft_reset bme68x_soft_reset + * \code + * int8_t bme68x_soft_reset(struct bme68x_dev *dev); + * \endcode + * @details This API soft-resets the sensor. + * + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_soft_reset(struct bme68x_dev *dev); + +/** + * \ingroup bme68x + * \defgroup bme68xApiOm Operation mode + * @brief API to configure operation mode + */ + +/*! + * \ingroup bme68xApiOm + * \page bme68x_api_bme68x_set_op_mode bme68x_set_op_mode + * \code + * int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev); + * \endcode + * @details This API is used to set the operation mode of the sensor + * @param[in] op_mode : Desired operation mode. + * @param[in] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_set_op_mode(const uint8_t op_mode, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiOm + * \page bme68x_api_bme68x_get_op_mode bme68x_get_op_mode + * \code + * int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev); + * \endcode + * @details This API is used to get the operation mode of the sensor. + * + * @param[out] op_mode : Desired operation mode. + * @param[in,out] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_get_op_mode(uint8_t *op_mode, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiConfig + * \page bme68x_api_bme68x_get_meas_dur bme68x_get_meas_dur + * \code + * uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev); + * \endcode + * @details This API is used to get the remaining duration that can be used for heating. + * + * @param[in] op_mode : Desired operation mode. + * @param[in] conf : Desired sensor configuration. + * @param[in] dev : Structure instance of bme68x_dev + * + * @return Measurement duration calculated in microseconds + */ +uint32_t bme68x_get_meas_dur(const uint8_t op_mode, struct bme68x_conf *conf, struct bme68x_dev *dev); + +/** + * \ingroup bme68x + * \defgroup bme68xApiData Data Read out + * @brief Read our data from the sensor + */ + +/*! + * \ingroup bme68xApiData + * \page bme68x_api_bme68x_get_data bme68x_get_data + * \code + * int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev); + * \endcode + * @details This API reads the pressure, temperature and humidity and gas data + * from the sensor, compensates the data and store it in the bme68x_data + * structure instance passed by the user. + * + * @param[in] op_mode : Expected operation mode. + * @param[out] data : Structure instance to hold the data. + * @param[out] n_data : Number of data instances available. + * @param[in,out] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_get_data(uint8_t op_mode, struct bme68x_data *data, uint8_t *n_data, struct bme68x_dev *dev); + +/** + * \ingroup bme68x + * \defgroup bme68xApiConfig Configuration + * @brief Configuration API of sensor + */ + +/*! + * \ingroup bme68xApiConfig + * \page bme68x_api_bme68x_set_conf bme68x_set_conf + * \code + * int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev); + * \endcode + * @details This API is used to set the oversampling, filter and odr configuration + * + * @param[in] conf : Desired sensor configuration. + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_set_conf(struct bme68x_conf *conf, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiConfig + * \page bme68x_api_bme68x_get_conf bme68x_get_conf + * \code + * int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev); + * \endcode + * @details This API is used to get the oversampling, filter and odr + * configuration + * + * @param[out] conf : Present sensor configuration. + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_get_conf(struct bme68x_conf *conf, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiConfig + * \page bme68x_api_bme68x_set_heatr_conf bme68x_set_heatr_conf + * \code + * int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev); + * \endcode + * @details This API is used to set the gas configuration of the sensor. + * + * @param[in] op_mode : Expected operation mode of the sensor. + * @param[in] conf : Desired heating configuration. + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_set_heatr_conf(uint8_t op_mode, const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiConfig + * \page bme68x_api_bme68x_get_heatr_conf bme68x_get_heatr_conf + * \code + * int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev); + * \endcode + * @details This API is used to get the gas configuration of the sensor. + * + * @param[out] conf : Current configurations of the gas sensor. + * @param[in,out] dev : Structure instance of bme68x_dev. + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_get_heatr_conf(const struct bme68x_heatr_conf *conf, struct bme68x_dev *dev); + +/*! + * \ingroup bme68xApiSystem + * \page bme68x_api_bme68x_selftest_check bme68x_selftest_check + * \code + * int8_t bme68x_selftest_check(const struct bme68x_dev *dev); + * \endcode + * @details This API performs Self-test of low gas variant of BME68X + * + * @param[in, out] dev : Structure instance of bme68x_dev + * + * @return Result of API execution status + * @retval 0 -> Success + * @retval < 0 -> Fail + */ +int8_t bme68x_selftest_check(const struct bme68x_dev *dev); + +#ifdef __cplusplus +} +#endif /* End of CPP guard */ +#endif /* BME68X_H_ */ diff --git a/src/bme68x/bme68x_defs.h b/src/bme68x/bme68x_defs.h new file mode 100644 index 0000000..861b2f7 --- /dev/null +++ b/src/bme68x/bme68x_defs.h @@ -0,0 +1,972 @@ +/** +* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bme68x_defs.h +* @date 2021-11-09 +* @version v4.4.7 +* +*/ + +/*! @cond DOXYGEN_SUPRESS */ + +#ifndef BME68X_DEFS_H_ +#define BME68X_DEFS_H_ + +/********************************************************* */ +/*! Header includes */ +/********************************************************* */ +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +/********************************************************* */ +/*! Common Macros */ +/********************************************************* */ +#ifdef __KERNEL__ +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif +#endif + +/*! C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +#ifndef BME68X_DO_NOT_USE_FPU + +/* Comment or un-comment the macro to provide floating point data output */ +#define BME68X_USE_FPU +#endif + +/* Period between two polls (value can be given by user) */ +#ifndef BME68X_PERIOD_POLL +#define BME68X_PERIOD_POLL UINT32_C(10000) +#endif + +/* BME68X unique chip identifier */ +#define BME68X_CHIP_ID UINT8_C(0x61) + +/* Period for a soft reset */ +#define BME68X_PERIOD_RESET UINT32_C(10000) + +/* BME68X lower I2C address */ +#define BME68X_I2C_ADDR_LOW UINT8_C(0x76) + +/* BME68X higher I2C address */ +#define BME68X_I2C_ADDR_HIGH UINT8_C(0x77) + +/* Soft reset command */ +#define BME68X_SOFT_RESET_CMD UINT8_C(0xb6) + +/* Return code definitions */ +/* Success */ +#define BME68X_OK INT8_C(0) + +/* Errors */ +/* Null pointer passed */ +#define BME68X_E_NULL_PTR INT8_C(-1) + +/* Communication failure */ +#define BME68X_E_COM_FAIL INT8_C(-2) + +/* Sensor not found */ +#define BME68X_E_DEV_NOT_FOUND INT8_C(-3) + +/* Incorrect length parameter */ +#define BME68X_E_INVALID_LENGTH INT8_C(-4) + +/* Self test fail error */ +#define BME68X_E_SELF_TEST INT8_C(-5) + +/* Warnings */ +/* Define a valid operation mode */ +#define BME68X_W_DEFINE_OP_MODE INT8_C(1) + +/* No new data was found */ +#define BME68X_W_NO_NEW_DATA INT8_C(2) + +/* Define the shared heating duration */ +#define BME68X_W_DEFINE_SHD_HEATR_DUR INT8_C(3) + +/* Information - only available via bme68x_dev.info_msg */ +#define BME68X_I_PARAM_CORR UINT8_C(1) + +/* Register map addresses in I2C */ +/* Register for 3rd group of coefficients */ +#define BME68X_REG_COEFF3 UINT8_C(0x00) + +/* 0th Field address*/ +#define BME68X_REG_FIELD0 UINT8_C(0x1d) + +/* 0th Current DAC address*/ +#define BME68X_REG_IDAC_HEAT0 UINT8_C(0x50) + +/* 0th Res heat address */ +#define BME68X_REG_RES_HEAT0 UINT8_C(0x5a) + +/* 0th Gas wait address */ +#define BME68X_REG_GAS_WAIT0 UINT8_C(0x64) + +/* Shared heating duration address */ +#define BME68X_REG_SHD_HEATR_DUR UINT8_C(0x6E) + +/* CTRL_GAS_0 address */ +#define BME68X_REG_CTRL_GAS_0 UINT8_C(0x70) + +/* CTRL_GAS_1 address */ +#define BME68X_REG_CTRL_GAS_1 UINT8_C(0x71) + +/* CTRL_HUM address */ +#define BME68X_REG_CTRL_HUM UINT8_C(0x72) + +/* CTRL_MEAS address */ +#define BME68X_REG_CTRL_MEAS UINT8_C(0x74) + +/* CONFIG address */ +#define BME68X_REG_CONFIG UINT8_C(0x75) + +/* MEM_PAGE address */ +#define BME68X_REG_MEM_PAGE UINT8_C(0xf3) + +/* Unique ID address */ +#define BME68X_REG_UNIQUE_ID UINT8_C(0x83) + +/* Register for 1st group of coefficients */ +#define BME68X_REG_COEFF1 UINT8_C(0x8a) + +/* Chip ID address */ +#define BME68X_REG_CHIP_ID UINT8_C(0xd0) + +/* Soft reset address */ +#define BME68X_REG_SOFT_RESET UINT8_C(0xe0) + +/* Register for 2nd group of coefficients */ +#define BME68X_REG_COEFF2 UINT8_C(0xe1) + +/* Variant ID Register */ +#define BME68X_REG_VARIANT_ID UINT8_C(0xF0) + +/* Enable/Disable macros */ + +/* Enable */ +#define BME68X_ENABLE UINT8_C(0x01) + +/* Disable */ +#define BME68X_DISABLE UINT8_C(0x00) + +/* Variant ID macros */ + +/* Low Gas variant */ +#define BME68X_VARIANT_GAS_LOW UINT8_C(0x00) + +/* High Gas variant */ +#define BME68X_VARIANT_GAS_HIGH UINT8_C(0x01) + +/* Oversampling setting macros */ + +/* Switch off measurement */ +#define BME68X_OS_NONE UINT8_C(0) + +/* Perform 1 measurement */ +#define BME68X_OS_1X UINT8_C(1) + +/* Perform 2 measurements */ +#define BME68X_OS_2X UINT8_C(2) + +/* Perform 4 measurements */ +#define BME68X_OS_4X UINT8_C(3) + +/* Perform 8 measurements */ +#define BME68X_OS_8X UINT8_C(4) + +/* Perform 16 measurements */ +#define BME68X_OS_16X UINT8_C(5) + +/* IIR Filter settings */ + +/* Switch off the filter */ +#define BME68X_FILTER_OFF UINT8_C(0) + +/* Filter coefficient of 2 */ +#define BME68X_FILTER_SIZE_1 UINT8_C(1) + +/* Filter coefficient of 4 */ +#define BME68X_FILTER_SIZE_3 UINT8_C(2) + +/* Filter coefficient of 8 */ +#define BME68X_FILTER_SIZE_7 UINT8_C(3) + +/* Filter coefficient of 16 */ +#define BME68X_FILTER_SIZE_15 UINT8_C(4) + +/* Filter coefficient of 32 */ +#define BME68X_FILTER_SIZE_31 UINT8_C(5) + +/* Filter coefficient of 64 */ +#define BME68X_FILTER_SIZE_63 UINT8_C(6) + +/* Filter coefficient of 128 */ +#define BME68X_FILTER_SIZE_127 UINT8_C(7) + +/* ODR/Standby time macros */ + +/* Standby time of 0.59ms */ +#define BME68X_ODR_0_59_MS UINT8_C(0) + +/* Standby time of 62.5ms */ +#define BME68X_ODR_62_5_MS UINT8_C(1) + +/* Standby time of 125ms */ +#define BME68X_ODR_125_MS UINT8_C(2) + +/* Standby time of 250ms */ +#define BME68X_ODR_250_MS UINT8_C(3) + +/* Standby time of 500ms */ +#define BME68X_ODR_500_MS UINT8_C(4) + +/* Standby time of 1s */ +#define BME68X_ODR_1000_MS UINT8_C(5) + +/* Standby time of 10ms */ +#define BME68X_ODR_10_MS UINT8_C(6) + +/* Standby time of 20ms */ +#define BME68X_ODR_20_MS UINT8_C(7) + +/* No standby time */ +#define BME68X_ODR_NONE UINT8_C(8) + +/* Operating mode macros */ + +/* Sleep operation mode */ +#define BME68X_SLEEP_MODE UINT8_C(0) + +/* Forced operation mode */ +#define BME68X_FORCED_MODE UINT8_C(1) + +/* Parallel operation mode */ +#define BME68X_PARALLEL_MODE UINT8_C(2) + +/* Sequential operation mode */ +#define BME68X_SEQUENTIAL_MODE UINT8_C(3) + +/* SPI page macros */ + +/* SPI memory page 0 */ +#define BME68X_MEM_PAGE0 UINT8_C(0x10) + +/* SPI memory page 1 */ +#define BME68X_MEM_PAGE1 UINT8_C(0x00) + +/* Coefficient index macros */ + +/* Length for all coefficients */ +#define BME68X_LEN_COEFF_ALL UINT8_C(42) + +/* Length for 1st group of coefficients */ +#define BME68X_LEN_COEFF1 UINT8_C(23) + +/* Length for 2nd group of coefficients */ +#define BME68X_LEN_COEFF2 UINT8_C(14) + +/* Length for 3rd group of coefficients */ +#define BME68X_LEN_COEFF3 UINT8_C(5) + +/* Length of the field */ +#define BME68X_LEN_FIELD UINT8_C(17) + +/* Length between two fields */ +#define BME68X_LEN_FIELD_OFFSET UINT8_C(17) + +/* Length of the configuration register */ +#define BME68X_LEN_CONFIG UINT8_C(5) + +/* Length of the interleaved buffer */ +#define BME68X_LEN_INTERLEAVE_BUFF UINT8_C(20) + +/* Coefficient index macros */ + +/* Coefficient T2 LSB position */ +#define BME68X_IDX_T2_LSB (0) + +/* Coefficient T2 MSB position */ +#define BME68X_IDX_T2_MSB (1) + +/* Coefficient T3 position */ +#define BME68X_IDX_T3 (2) + +/* Coefficient P1 LSB position */ +#define BME68X_IDX_P1_LSB (4) + +/* Coefficient P1 MSB position */ +#define BME68X_IDX_P1_MSB (5) + +/* Coefficient P2 LSB position */ +#define BME68X_IDX_P2_LSB (6) + +/* Coefficient P2 MSB position */ +#define BME68X_IDX_P2_MSB (7) + +/* Coefficient P3 position */ +#define BME68X_IDX_P3 (8) + +/* Coefficient P4 LSB position */ +#define BME68X_IDX_P4_LSB (10) + +/* Coefficient P4 MSB position */ +#define BME68X_IDX_P4_MSB (11) + +/* Coefficient P5 LSB position */ +#define BME68X_IDX_P5_LSB (12) + +/* Coefficient P5 MSB position */ +#define BME68X_IDX_P5_MSB (13) + +/* Coefficient P7 position */ +#define BME68X_IDX_P7 (14) + +/* Coefficient P6 position */ +#define BME68X_IDX_P6 (15) + +/* Coefficient P8 LSB position */ +#define BME68X_IDX_P8_LSB (18) + +/* Coefficient P8 MSB position */ +#define BME68X_IDX_P8_MSB (19) + +/* Coefficient P9 LSB position */ +#define BME68X_IDX_P9_LSB (20) + +/* Coefficient P9 MSB position */ +#define BME68X_IDX_P9_MSB (21) + +/* Coefficient P10 position */ +#define BME68X_IDX_P10 (22) + +/* Coefficient H2 MSB position */ +#define BME68X_IDX_H2_MSB (23) + +/* Coefficient H2 LSB position */ +#define BME68X_IDX_H2_LSB (24) + +/* Coefficient H1 LSB position */ +#define BME68X_IDX_H1_LSB (24) + +/* Coefficient H1 MSB position */ +#define BME68X_IDX_H1_MSB (25) + +/* Coefficient H3 position */ +#define BME68X_IDX_H3 (26) + +/* Coefficient H4 position */ +#define BME68X_IDX_H4 (27) + +/* Coefficient H5 position */ +#define BME68X_IDX_H5 (28) + +/* Coefficient H6 position */ +#define BME68X_IDX_H6 (29) + +/* Coefficient H7 position */ +#define BME68X_IDX_H7 (30) + +/* Coefficient T1 LSB position */ +#define BME68X_IDX_T1_LSB (31) + +/* Coefficient T1 MSB position */ +#define BME68X_IDX_T1_MSB (32) + +/* Coefficient GH2 LSB position */ +#define BME68X_IDX_GH2_LSB (33) + +/* Coefficient GH2 MSB position */ +#define BME68X_IDX_GH2_MSB (34) + +/* Coefficient GH1 position */ +#define BME68X_IDX_GH1 (35) + +/* Coefficient GH3 position */ +#define BME68X_IDX_GH3 (36) + +/* Coefficient res heat value position */ +#define BME68X_IDX_RES_HEAT_VAL (37) + +/* Coefficient res heat range position */ +#define BME68X_IDX_RES_HEAT_RANGE (39) + +/* Coefficient range switching error position */ +#define BME68X_IDX_RANGE_SW_ERR (41) + +/* Gas measurement macros */ + +/* Disable gas measurement */ +#define BME68X_DISABLE_GAS_MEAS UINT8_C(0x00) + +/* Enable gas measurement low */ +#define BME68X_ENABLE_GAS_MEAS_L UINT8_C(0x01) + +/* Enable gas measurement high */ +#define BME68X_ENABLE_GAS_MEAS_H UINT8_C(0x02) + +/* Heater control macros */ + +/* Enable heater */ +#define BME68X_ENABLE_HEATER UINT8_C(0x00) + +/* Disable heater */ +#define BME68X_DISABLE_HEATER UINT8_C(0x01) + +#ifdef BME68X_USE_FPU + +/* 0 degree Celsius */ +#define BME68X_MIN_TEMPERATURE INT16_C(0) + +/* 60 degree Celsius */ +#define BME68X_MAX_TEMPERATURE INT16_C(60) + +/* 900 hecto Pascals */ +#define BME68X_MIN_PRESSURE UINT32_C(90000) + +/* 1100 hecto Pascals */ +#define BME68X_MAX_PRESSURE UINT32_C(110000) + +/* 20% relative humidity */ +#define BME68X_MIN_HUMIDITY UINT32_C(20) + +/* 80% relative humidity*/ +#define BME68X_MAX_HUMIDITY UINT32_C(80) +#else + +/* 0 degree Celsius */ +#define BME68X_MIN_TEMPERATURE INT16_C(0) + +/* 60 degree Celsius */ +#define BME68X_MAX_TEMPERATURE INT16_C(6000) + +/* 900 hecto Pascals */ +#define BME68X_MIN_PRESSURE UINT32_C(90000) + +/* 1100 hecto Pascals */ +#define BME68X_MAX_PRESSURE UINT32_C(110000) + +/* 20% relative humidity */ +#define BME68X_MIN_HUMIDITY UINT32_C(20000) + +/* 80% relative humidity*/ +#define BME68X_MAX_HUMIDITY UINT32_C(80000) + +#endif + +#define BME68X_HEATR_DUR1 UINT16_C(1000) +#define BME68X_HEATR_DUR2 UINT16_C(2000) +#define BME68X_HEATR_DUR1_DELAY UINT32_C(1000000) +#define BME68X_HEATR_DUR2_DELAY UINT32_C(2000000) +#define BME68X_N_MEAS UINT8_C(6) +#define BME68X_LOW_TEMP UINT8_C(150) +#define BME68X_HIGH_TEMP UINT16_C(350) + +/* Mask macros */ +/* Mask for number of conversions */ +#define BME68X_NBCONV_MSK UINT8_C(0X0f) + +/* Mask for IIR filter */ +#define BME68X_FILTER_MSK UINT8_C(0X1c) + +/* Mask for ODR[3] */ +#define BME68X_ODR3_MSK UINT8_C(0x80) + +/* Mask for ODR[2:0] */ +#define BME68X_ODR20_MSK UINT8_C(0xe0) + +/* Mask for temperature oversampling */ +#define BME68X_OST_MSK UINT8_C(0Xe0) + +/* Mask for pressure oversampling */ +#define BME68X_OSP_MSK UINT8_C(0X1c) + +/* Mask for humidity oversampling */ +#define BME68X_OSH_MSK UINT8_C(0X07) + +/* Mask for heater control */ +#define BME68X_HCTRL_MSK UINT8_C(0x08) + +/* Mask for run gas */ +#define BME68X_RUN_GAS_MSK UINT8_C(0x30) + +/* Mask for operation mode */ +#define BME68X_MODE_MSK UINT8_C(0x03) + +/* Mask for res heat range */ +#define BME68X_RHRANGE_MSK UINT8_C(0x30) + +/* Mask for range switching error */ +#define BME68X_RSERROR_MSK UINT8_C(0xf0) + +/* Mask for new data */ +#define BME68X_NEW_DATA_MSK UINT8_C(0x80) + +/* Mask for gas index */ +#define BME68X_GAS_INDEX_MSK UINT8_C(0x0f) + +/* Mask for gas range */ +#define BME68X_GAS_RANGE_MSK UINT8_C(0x0f) + +/* Mask for gas measurement valid */ +#define BME68X_GASM_VALID_MSK UINT8_C(0x20) + +/* Mask for heater stability */ +#define BME68X_HEAT_STAB_MSK UINT8_C(0x10) + +/* Mask for SPI memory page */ +#define BME68X_MEM_PAGE_MSK UINT8_C(0x10) + +/* Mask for reading a register in SPI */ +#define BME68X_SPI_RD_MSK UINT8_C(0x80) + +/* Mask for writing a register in SPI */ +#define BME68X_SPI_WR_MSK UINT8_C(0x7f) + +/* Mask for the H1 calibration coefficient */ +#define BME68X_BIT_H1_DATA_MSK UINT8_C(0x0f) + +/* Position macros */ + +/* Filter bit position */ +#define BME68X_FILTER_POS UINT8_C(2) + +/* Temperature oversampling bit position */ +#define BME68X_OST_POS UINT8_C(5) + +/* Pressure oversampling bit position */ +#define BME68X_OSP_POS UINT8_C(2) + +/* ODR[3] bit position */ +#define BME68X_ODR3_POS UINT8_C(7) + +/* ODR[2:0] bit position */ +#define BME68X_ODR20_POS UINT8_C(5) + +/* Run gas bit position */ +#define BME68X_RUN_GAS_POS UINT8_C(4) + +/* Heater control bit position */ +#define BME68X_HCTRL_POS UINT8_C(3) + +/* Macro to combine two 8 bit data's to form a 16 bit data */ +#define BME68X_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) + +/* Macro to set bits */ +#define BME68X_SET_BITS(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + ((data << bitname##_POS) & bitname##_MSK)) + +/* Macro to get bits */ +#define BME68X_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \ + (bitname##_POS)) + +/* Macro to set bits starting from position 0 */ +#define BME68X_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + (data & bitname##_MSK)) + +/* Macro to get bits starting from position 0 */ +#define BME68X_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +/** + * BME68X_INTF_RET_TYPE is the read/write interface return type which can be overwritten by the build system. + * The default is set to int8_t. + */ +#ifndef BME68X_INTF_RET_TYPE +#define BME68X_INTF_RET_TYPE int8_t +#endif + +/** + * BME68X_INTF_RET_SUCCESS is the success return value read/write interface return type which can be + * overwritten by the build system. The default is set to 0. It is used to check for a successful + * execution of the read/write functions + */ +#ifndef BME68X_INTF_RET_SUCCESS +#define BME68X_INTF_RET_SUCCESS INT8_C(0) +#endif + +/********************************************************* */ +/*! Function Pointers */ +/********************************************************* */ + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific read functions of the user + * + * @param[in] reg_addr : 8bit register address of the sensor + * @param[out] reg_data : Data from the specified address + * @param[in] length : Length of the reg_data array + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + * @retval 0 for Success + * @retval Non-zero for Failure + */ +typedef BME68X_INTF_RET_TYPE (*bme68x_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, + void *intf_ptr); + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific write functions of the user + * + * @param[in] reg_addr : 8bit register address of the sensor + * @param[out] reg_data : Data to the specified address + * @param[in] length : Length of the reg_data array + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + * @retval 0 for Success + * @retval Non-zero for Failure + * + */ +typedef BME68X_INTF_RET_TYPE (*bme68x_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, + void *intf_ptr); + +/*! + * @brief Delay function pointer which should be mapped to + * delay function of the user + * + * @param period - The time period in microseconds + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + */ +typedef void (*bme68x_delay_us_fptr_t)(uint32_t period, void *intf_ptr); + +/* + * @brief Generic communication function pointer + * @param[in] dev_id: Place holder to store the id of the device structure + * Can be used to store the index of the Chip select or + * I2C address of the device. + * @param[in] reg_addr: Used to select the register the where data needs to + * be read from or written to. + * @param[in,out] reg_data: Data array to read/write + * @param[in] len: Length of the data array + */ + +/* + * @brief Interface selection Enumerations + */ +enum bme68x_intf { + /*! SPI interface */ + BME68X_SPI_INTF, + /*! I2C interface */ + BME68X_I2C_INTF +}; + +/* Structure definitions */ + +/* + * @brief Sensor field data structure + */ +struct bme68x_data +{ + /*! Contains new_data, gasm_valid & heat_stab */ + uint8_t status; + + /*! The index of the heater profile used */ + uint8_t gas_index; + + /*! Measurement index to track order */ + uint8_t meas_index; + + /*! Heater resistance */ + uint8_t res_heat; + + /*! Current DAC */ + uint8_t idac; + + /*! Gas wait period */ + uint8_t gas_wait; +#ifndef BME68X_USE_FPU + + /*! Temperature in degree celsius x100 */ + int16_t temperature; + + /*! Pressure in Pascal */ + uint32_t pressure; + + /*! Humidity in % relative humidity x1000 */ + uint32_t humidity; + + /*! Gas resistance in Ohms */ + uint32_t gas_resistance; +#else + + /*! Temperature in degree celsius */ + float temperature; + + /*! Pressure in Pascal */ + float pressure; + + /*! Humidity in % relative humidity x1000 */ + float humidity; + + /*! Gas resistance in Ohms */ + float gas_resistance; + +#endif + +}; + +/* + * @brief Structure to hold the calibration coefficients + */ +struct bme68x_calib_data +{ + /*! Calibration coefficient for the humidity sensor */ + uint16_t par_h1; + + /*! Calibration coefficient for the humidity sensor */ + uint16_t par_h2; + + /*! Calibration coefficient for the humidity sensor */ + int8_t par_h3; + + /*! Calibration coefficient for the humidity sensor */ + int8_t par_h4; + + /*! Calibration coefficient for the humidity sensor */ + int8_t par_h5; + + /*! Calibration coefficient for the humidity sensor */ + uint8_t par_h6; + + /*! Calibration coefficient for the humidity sensor */ + int8_t par_h7; + + /*! Calibration coefficient for the gas sensor */ + int8_t par_gh1; + + /*! Calibration coefficient for the gas sensor */ + int16_t par_gh2; + + /*! Calibration coefficient for the gas sensor */ + int8_t par_gh3; + + /*! Calibration coefficient for the temperature sensor */ + uint16_t par_t1; + + /*! Calibration coefficient for the temperature sensor */ + int16_t par_t2; + + /*! Calibration coefficient for the temperature sensor */ + int8_t par_t3; + + /*! Calibration coefficient for the pressure sensor */ + uint16_t par_p1; + + /*! Calibration coefficient for the pressure sensor */ + int16_t par_p2; + + /*! Calibration coefficient for the pressure sensor */ + int8_t par_p3; + + /*! Calibration coefficient for the pressure sensor */ + int16_t par_p4; + + /*! Calibration coefficient for the pressure sensor */ + int16_t par_p5; + + /*! Calibration coefficient for the pressure sensor */ + int8_t par_p6; + + /*! Calibration coefficient for the pressure sensor */ + int8_t par_p7; + + /*! Calibration coefficient for the pressure sensor */ + int16_t par_p8; + + /*! Calibration coefficient for the pressure sensor */ + int16_t par_p9; + + /*! Calibration coefficient for the pressure sensor */ + uint8_t par_p10; +#ifndef BME68X_USE_FPU + + /*! Variable to store the intermediate temperature coefficient */ + int32_t t_fine; +#else + + /*! Variable to store the intermediate temperature coefficient */ + float t_fine; +#endif + + /*! Heater resistance range coefficient */ + uint8_t res_heat_range; + + /*! Heater resistance value coefficient */ + int8_t res_heat_val; + + /*! Gas resistance range switching error coefficient */ + int8_t range_sw_err; +}; + +/* + * @brief BME68X sensor settings structure which comprises of ODR, + * over-sampling and filter settings. + */ +struct bme68x_conf +{ + /*! Humidity oversampling. Refer @ref osx*/ + uint8_t os_hum; + + /*! Temperature oversampling. Refer @ref osx */ + uint8_t os_temp; + + /*! Pressure oversampling. Refer @ref osx */ + uint8_t os_pres; + + /*! Filter coefficient. Refer @ref filter*/ + uint8_t filter; + + /*! + * Standby time between sequential mode measurement profiles. + * Refer @ref odr + */ + uint8_t odr; +}; + +/* + * @brief BME68X gas heater configuration + */ +struct bme68x_heatr_conf +{ + /*! Enable gas measurement. Refer @ref en_dis */ + uint8_t enable; + + /*! Store the heater temperature for forced mode degree Celsius */ + uint16_t heatr_temp; + + /*! Store the heating duration for forced mode in milliseconds */ + uint16_t heatr_dur; + + /*! Store the heater temperature profile in degree Celsius */ + uint16_t *heatr_temp_prof; + + /*! Store the heating duration profile in milliseconds */ + uint16_t *heatr_dur_prof; + + /*! Variable to store the length of the heating profile */ + uint8_t profile_len; + + /*! + * Variable to store heating duration for parallel mode + * in milliseconds + */ + uint16_t shared_heatr_dur; +}; + +/* + * @brief BME68X device structure + */ +struct bme68x_dev +{ + /*! Chip Id */ + uint8_t chip_id; + + /*! + * The interface pointer is used to enable the user + * to link their interface descriptors for reference during the + * implementation of the read and write interfaces to the + * hardware. + */ + void *intf_ptr; + + /*! + * Variant id + * ---------------------------------------- + * Value | Variant + * ---------------------------------------- + * 0 | BME68X_VARIANT_GAS_LOW + * 1 | BME68X_VARIANT_GAS_HIGH + * ---------------------------------------- + */ + uint32_t variant_id; + + /*! SPI/I2C interface */ + enum bme68x_intf intf; + + /*! Memory page used */ + uint8_t mem_page; + + /*! Ambient temperature in Degree C*/ + int8_t amb_temp; + + /*! Sensor calibration data */ + struct bme68x_calib_data calib; + + /*! Read function pointer */ + bme68x_read_fptr_t read; + + /*! Write function pointer */ + bme68x_write_fptr_t write; + + /*! Delay function pointer */ + bme68x_delay_us_fptr_t delay_us; + + /*! To store interface pointer error */ + BME68X_INTF_RET_TYPE intf_rslt; + + /*! Store the info messages */ + uint8_t info_msg; +}; + +#endif /* BME68X_DEFS_H_ */ +/*! @endcond */ diff --git a/src/bsec.cpp b/src/bsec.cpp index 6e673c4..f0d20d6 100644 --- a/src/bsec.cpp +++ b/src/bsec.cpp @@ -29,10 +29,11 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * - * @file bsec.cpp - * @date 18 Nov 2020 - * + * + * @file bsec.cpp + * @date 27 May 2022 + * @version 1.4.1492 + * */ #include "bsec.h" @@ -45,78 +46,60 @@ SPIClass* Bsec::spiObj = NULL; */ Bsec::Bsec() { - nextCall = 0; - version.major = 0; - version.minor = 0; - version.major_bugfix = 0; - version.minor_bugfix = 0; - millisOverflowCounter = 0; - lastTime = 0; - bme680Status = BME680_OK; - outputTimestamp = 0; - _tempOffset = 0.0f; - status = BSEC_OK; - bsecConfig = NULL; - nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR; - zeroOutputs(); + zeroInputs(); + zeroOutputs(); } /** - * @brief Function to initialize the BSEC library and the BME680 sensor + * @brief Function to initialize the BSEC library and the BME68x sensor */ -void Bsec::begin(uint8_t devId, - enum bme680_intf intf, - bme680_com_fptr_t read, - bme680_com_fptr_t write, - bme680_delay_fptr_t idleTask) +void Bsec::begin(bme68x_intf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write, bme68x_delay_us_fptr_t idleTask, void *intfPtr) { - _bme680.dev_id = devId; - _bme680.intf = intf; - _bme680.read = read; - _bme680.write = write; - _bme680.delay_ms = idleTask; - _bme680.amb_temp = 25; - _bme680.power_mode = BME680_FORCED_MODE; - - beginCommon(); + _bme68x.intf = intf; + _bme68x.read = read; + _bme68x.write = write; + _bme68x.delay_us = idleTask; + _bme68x.intf_ptr = intfPtr; + _bme68x.amb_temp = 25; + + beginCommon(); } /** - * @brief Function to initialize the BSEC library and the BME680 sensor + * @brief Function to initialize the BSEC library and the BME68x sensor */ -void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c, bme680_delay_fptr_t idleTask) +void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c) { - _bme680.dev_id = i2cAddr; - _bme680.intf = BME680_I2C_INTF; - _bme680.read = Bsec::i2cRead; - _bme680.write = Bsec::i2cWrite; - _bme680.delay_ms = idleTask; - _bme680.amb_temp = 25; - _bme680.power_mode = BME680_FORCED_MODE; - - Bsec::wireObj = &i2c; - - beginCommon(); + _bme68x.intf_ptr = (void*)(intptr_t)i2cAddr; + _bme68x.intf = BME68X_I2C_INTF; + _bme68x.read = Bsec::i2cRead; + _bme68x.write = Bsec::i2cWrite; + _bme68x.delay_us = Bsec::delay_us; + _bme68x.amb_temp = 25; + + Bsec::wireObj = &i2c; + Bsec::wireObj->begin(); + beginCommon(); } /** - * @brief Function to initialize the BSEC library and the BME680 sensor + * @brief Function to initialize the BSEC library and the BME68X sensor with SPI communication setting */ -void Bsec::begin(uint8_t chipSelect, SPIClass &spi, bme680_delay_fptr_t idleTask) +void Bsec::begin(uint8_t chipSelect, SPIClass &spi) { - _bme680.dev_id = chipSelect; - _bme680.intf = BME680_SPI_INTF; - _bme680.read = Bsec::spiTransfer; - _bme680.write = Bsec::spiTransfer; - _bme680.delay_ms = idleTask; - _bme680.amb_temp = 25; - _bme680.power_mode = BME680_FORCED_MODE; - - pinMode(chipSelect, OUTPUT); - digitalWrite(chipSelect, HIGH); - Bsec::spiObj = &spi; - - beginCommon(); + _bme68x.intf_ptr = (void*)(intptr_t)chipSelect; + _bme68x.intf = BME68X_SPI_INTF; + _bme68x.read = Bsec::spiRead; + _bme68x.write = Bsec::spiWrite; + _bme68x.delay_us = Bsec::delay_us; + _bme68x.amb_temp = 25; + + pinMode(chipSelect, OUTPUT); + digitalWrite(chipSelect, HIGH); + Bsec::spiObj = &spi; + Bsec::spiObj->begin(); + + return beginCommon(); } /** @@ -124,41 +107,14 @@ void Bsec::begin(uint8_t chipSelect, SPIClass &spi, bme680_delay_fptr_t idleTask */ void Bsec::beginCommon(void) { - virtualSensors[0].sensor_id = BSEC_OUTPUT_IAQ; - virtualSensors[1].sensor_id = BSEC_OUTPUT_STATIC_IAQ; - virtualSensors[2].sensor_id = BSEC_OUTPUT_CO2_EQUIVALENT; - virtualSensors[3].sensor_id = BSEC_OUTPUT_BREATH_VOC_EQUIVALENT; - virtualSensors[4].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE; - virtualSensors[5].sensor_id = BSEC_OUTPUT_RAW_PRESSURE; - virtualSensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY; - virtualSensors[7].sensor_id = BSEC_OUTPUT_RAW_GAS; - virtualSensors[8].sensor_id = BSEC_OUTPUT_STABILIZATION_STATUS; - virtualSensors[9].sensor_id = BSEC_OUTPUT_RUN_IN_STATUS; - virtualSensors[10].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE; - virtualSensors[11].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY; - virtualSensors[12].sensor_id = BSEC_OUTPUT_COMPENSATED_GAS; - virtualSensors[13].sensor_id = BSEC_OUTPUT_GAS_PERCENTAGE; - - virtualSensors[0].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[1].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[2].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[3].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[4].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[5].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[6].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[7].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[8].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[9].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[10].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[11].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[12].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - virtualSensors[13].sample_rate = BSEC_SAMPLE_RATE_DISABLED; - - status = bsec_init(); - - getVersion(); - - bme680Status = bme680_init(&_bme680); + zeroInputs(); + zeroOutputs(); + + bsecStatus = bsec_init(); + + getVersion(); + + bme68xStatus = bme68x_init(&_bme68x); } /** @@ -166,93 +122,49 @@ void Bsec::beginCommon(void) */ void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate) { - for (uint8_t i = 0; i < nSensors; i++) - { - for (uint8_t j = 0; j < BSEC_NUMBER_OUTPUTS; j++) - { - if (virtualSensors[j].sensor_id == sensorList[i]) - { - virtualSensors[j].sample_rate = sampleRate; - } - } - } + bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS], + sensorSettings[BSEC_MAX_PHYSICAL_SENSOR]; + uint8_t nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR; - status = bsec_update_subscription(virtualSensors, BSEC_NUMBER_OUTPUTS, sensorSettings, &nSensorSettings); + for (uint8_t i = 0; i < nSensors; i++) { + virtualSensors[i].sensor_id = sensorList[i]; + virtualSensors[i].sample_rate = sampleRate; + } - return; + bsecStatus = bsec_update_subscription(virtualSensors, nSensors, sensorSettings, &nSensorSettings); + return; } /** - * @brief Callback from the user to trigger reading of data from the BME680, process and store outputs + * @brief Callback from the user to trigger reading of data from the BME68x, process and store outputs */ -bool Bsec::run(int64_t timeMilliseconds) +bool Bsec::run(void) { - bool newData = false; - - /* Check if the time has arrived to call do_steps() */ - int64_t callTimeMs = timeMilliseconds; - - if (callTimeMs < 0) /* Use millis */ - { - callTimeMs = getTimeMs(); - } - - if (callTimeMs >= nextCall) - { - bsec_init(); - - if (validBsecState) - { - setState(bsecState); - } - - nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR; - status = bsec_update_subscription(virtualSensors, BSEC_NUMBER_OUTPUTS, sensorSettings, &nSensorSettings); - - bsec_bme_settings_t bme680Settings; - - int64_t callTimeNs = callTimeMs * INT64_C(1000000); - - status = bsec_sensor_control(callTimeNs, &bme680Settings); - if (status < BSEC_OK) - { - return false; - } - - nextCall = bme680Settings.next_call / INT64_C(1000000); /* Convert from ns to ms */ - - bme680Status = setBme680Config(bme680Settings); - if (bme680Status != BME680_OK) - { - return false; - } - - bme680Status = bme680_set_sensor_mode(&_bme680); - if (bme680Status != BME680_OK) - { - return false; - } - - /* Wait for measurement to complete */ - uint16_t meas_dur = 0; - - bme680_get_profile_dur(&meas_dur, &_bme680); - _bme680.delay_ms(meas_dur); - - newData = readProcessData(callTimeNs + (meas_dur * INT64_C(1000000)), bme680Settings); - - uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; - uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE; - status = bsec_get_state(0, - bsecState, - BSEC_MAX_STATE_BLOB_SIZE, - workBuffer, - BSEC_MAX_STATE_BLOB_SIZE, - &n_serialized_state); - validBsecState = true; - } - - return newData; + bool newData = false; + /* Check if the time has arrived to call do_steps() */ + int64_t callTimeMs = getTimeMs(); + + if (callTimeMs >= nextCall) { + + bsec_bme_settings_t bme68xSettings; + + int64_t callTimeNs = callTimeMs * INT64_C(1000000); + + bsecStatus = bsec_sensor_control(callTimeNs, &bme68xSettings); + if (bsecStatus < BSEC_OK) + return false; + + nextCall = bme68xSettings.next_call / INT64_C(1000000); // Convert from ns to ms + + bme68xStatus = setBme68xConfig(bme68xSettings); + if (bme68xStatus != BME68X_OK) { + return false; + } + + newData = readProcessData(callTimeNs, bme68xSettings); + } + + return newData; } /** @@ -260,20 +172,9 @@ bool Bsec::run(int64_t timeMilliseconds) */ void Bsec::getState(uint8_t *state) { - uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; - uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE; - - if (!validBsecState) - { - status = bsec_get_state(0, - bsecState, - BSEC_MAX_STATE_BLOB_SIZE, - workBuffer, - BSEC_MAX_STATE_BLOB_SIZE, - &n_serialized_state); - validBsecState = true; - } - memcpy(state, bsecState, BSEC_MAX_STATE_BLOB_SIZE); + uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; + uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE; + bsecStatus = bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE, &n_serialized_state); } /** @@ -281,30 +182,19 @@ void Bsec::getState(uint8_t *state) */ void Bsec::setState(uint8_t *state) { - uint8_t workBuffer[BSEC_MAX_WORKBUFFER_SIZE]; - - status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, sizeof(workBuffer)); + uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; - if (status == BSEC_OK) - { - for (uint32_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) - { - bsecState[i] = state[i]; - } - validBsecState = true; - } + bsecStatus = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_STATE_BLOB_SIZE); } /** * @brief Function to set the configuration of the algorithm from memory */ -void Bsec::setConfig(const uint8_t *config) +void Bsec::setConfig(const uint8_t *state) { - uint8_t workBuffer[BSEC_MAX_WORKBUFFER_SIZE]; - - bsecConfig = (uint8_t *)config; + uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; - status = bsec_set_configuration(config, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, sizeof(workBuffer)); + bsecStatus = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, sizeof(workBuffer)); } /* Private functions */ @@ -314,303 +204,373 @@ void Bsec::setConfig(const uint8_t *config) */ void Bsec::getVersion(void) { - bsec_get_version(&version); + bsec_get_version(&version); } /** - * @brief Read data from the BME680 and process it + * @brief Read data from the BME68x and process it */ -bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings) +bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme68xSettings) { - bme680Status = bme680_get_sensor_data(&_data, &_bme680); - if (bme680Status != BME680_OK) - { - return false; - } - - bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; /* Temperature, Pressure, Humidity & Gas Resistance */ - uint8_t nInputs = 0, nOutputs = 0; - - if (_data.status & BME680_NEW_DATA_MSK) - { - if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) - { - inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE; -#ifdef BME680_FLOAT_POINT_COMPENSATION - inputs[nInputs].signal = _data.temperature; -#else - inputs[nInputs].signal = _data.temperature / 100.0f; -#endif - inputs[nInputs].time_stamp = currTimeNs; - nInputs++; - - /* Temperature offset from the real temperature due to external heat sources */ - inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE; - inputs[nInputs].signal = _tempOffset; - inputs[nInputs].time_stamp = currTimeNs; - nInputs++; - } - if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) - { - inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY; -#ifdef BME680_FLOAT_POINT_COMPENSATION - inputs[nInputs].signal = _data.humidity; -#else - inputs[nInputs].signal = _data.humidity / 1000.0f; -#endif - inputs[nInputs].time_stamp = currTimeNs; - nInputs++; - } - if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE) - { - inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE; - inputs[nInputs].signal = _data.pressure; - inputs[nInputs].time_stamp = currTimeNs; - nInputs++; - } - if (bme680Settings.process_data & BSEC_PROCESS_GAS) - { - inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR; - inputs[nInputs].signal = _data.gas_resistance; - inputs[nInputs].time_stamp = currTimeNs; - nInputs++; - } - } + bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temperature, Pressure, Humidity & Gas Resistance + uint8_t nInputs = 0, nOutputs = 0; + nFields = 0; + + if (bme68xSettings.process_data) + { + bme68xStatus = bme68x_get_data(BME68X_FORCED_MODE, &_data, &nFields, &_bme68x); + if (bme68xStatus != BME68X_OK) + { + return false; + } + + if (nFields) + { + if (bme68xSettings.process_data & BSEC_PROCESS_TEMPERATURE) + { + inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE; + inputs[nInputs].signal = _data.temperature; + + inputs[nInputs].time_stamp = currTimeNs; + nInputs++; + /* Temperature offset from the real temperature due to external heat sources */ + inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE; + inputs[nInputs].signal = _tempOffset; + inputs[nInputs].time_stamp = currTimeNs; + nInputs++; + } + if (bme68xSettings.process_data & BSEC_PROCESS_HUMIDITY) + { + inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY; + + inputs[nInputs].signal = _data.humidity; + + inputs[nInputs].time_stamp = currTimeNs; + nInputs++; + } + if (bme68xSettings.process_data & BSEC_PROCESS_PRESSURE) + { + inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE; + inputs[nInputs].signal = _data.pressure; + inputs[nInputs].time_stamp = currTimeNs; + nInputs++; + } + if (bme68xSettings.process_data & BSEC_PROCESS_GAS) + { + /* Check whether gas_valid flag is set */ + if (_data.status & BME68X_GASM_VALID_MSK) + { + inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR; + inputs[nInputs].signal = _data.gas_resistance; + inputs[nInputs].time_stamp = currTimeNs; + nInputs++; + } + } + } + } + + if (nInputs > 0) + { + nOutputs = BSEC_NUMBER_OUTPUTS; + bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS]; + + bsecStatus = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs); + if (bsecStatus != BSEC_OK) + return false; + + zeroOutputs(); + + if (nOutputs > 0) + { + outputTimestamp = _outputs[0].time_stamp / 1000000; // Convert from ns to ms + + for (uint8_t i = 0; i < nOutputs; i++) + { + switch (_outputs[i].sensor_id) + { + case BSEC_OUTPUT_IAQ: + iaq = _outputs[i].signal; + iaqAccuracy = _outputs[i].accuracy; + break; + case BSEC_OUTPUT_STATIC_IAQ: + staticIaq = _outputs[i].signal; + staticIaqAccuracy = _outputs[i].accuracy; + break; + case BSEC_OUTPUT_CO2_EQUIVALENT: + co2Equivalent = _outputs[i].signal; + co2Accuracy = _outputs[i].accuracy; + break; + case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: + breathVocEquivalent = _outputs[i].signal; + breathVocAccuracy = _outputs[i].accuracy; + break; + case BSEC_OUTPUT_RAW_TEMPERATURE: + rawTemperature = _outputs[i].signal; + break; + case BSEC_OUTPUT_RAW_PRESSURE: + pressure = _outputs[i].signal; + break; + case BSEC_OUTPUT_RAW_HUMIDITY: + rawHumidity = _outputs[i].signal; + break; + case BSEC_OUTPUT_RAW_GAS: + gasResistance = _outputs[i].signal; + break; + case BSEC_OUTPUT_STABILIZATION_STATUS: + stabStatus = _outputs[i].signal; + break; + case BSEC_OUTPUT_RUN_IN_STATUS: + runInStatus = _outputs[i].signal; + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: + temperature = _outputs[i].signal; + break; + case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: + humidity = _outputs[i].signal; + break; + case BSEC_OUTPUT_GAS_PERCENTAGE: + gasPercentage = _outputs[i].signal; + gasPercentageAccuracy = _outputs[i].accuracy; + break; + default: + continue; + } + } + return true; + } + } + + return false; +} - if (nInputs > 0) +/** + * @brief Set the BME68x sensor's configuration + */ +int8_t Bsec::setBme68xConfig(bsec_bme_settings_t bme68xSettings) +{ + int8_t bme68xSts = BME68X_OK; + uint16_t meas_period; + uint8_t current_op_mode; + + /* Check if a forced-mode measurement should be triggered now */ + if (bme68xSettings.trigger_measurement) + { + conf.filter = BME68X_FILTER_OFF; + conf.odr = BME68X_ODR_NONE; + conf.os_hum = bme68xSettings.humidity_oversampling; + conf.os_temp = bme68xSettings.temperature_oversampling; + conf.os_pres = bme68xSettings.pressure_oversampling; + + bme68xSts = bme68x_set_conf(&conf, &_bme68x); + + if (bme68xSts == BME68X_ERROR) + { + return bme68xSts; + } + + heatrConf.enable = bme68xSettings.run_gas; + heatrConf.heatr_temp = bme68xSettings.heater_temperature; + heatrConf.heatr_dur = bme68xSettings.heating_duration; + + bme68xSts = bme68x_set_heatr_conf(BME68X_FORCED_MODE, &heatrConf, &_bme68x); + + if (bme68xSts == BME68X_ERROR) + { + return bme68xSts; + } + + bme68xSts = bme68x_set_op_mode(BME68X_FORCED_MODE, &_bme68x); + + if (bme68xSts == BME68X_ERROR) + { + return bme68xSts; + } + meas_period = bme68x_get_meas_dur(BME68X_FORCED_MODE, &conf, &_bme68x) + heatrConf.heatr_dur*1000; + /* Delay till the measurement is ready. Timestamp resolution in ms */ + delay_us((uint32_t)meas_period, _bme68x.intf_ptr); + } + + /* Call the API to get current operation mode of the sensor */ + bme68xSts = bme68x_get_op_mode(¤t_op_mode, &_bme68x); + /* When the measurement is completed and data is ready for reading, the sensor must be in bme68x_SLEEP_MODE. + * Read operation mode to check whether measurement is completely done and wait until the sensor is no more + * in bme68x_FORCED_MODE. */ + while (current_op_mode == BME68X_FORCED_MODE) { - nOutputs = BSEC_NUMBER_OUTPUTS; - bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS]; - - status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs); - if (status != BSEC_OK) - { - return false; - } - - zeroOutputs(); - - if (nOutputs > 0) - { - outputTimestamp = _outputs[0].time_stamp / 1000000; /* Convert from ns to ms */ - - for (uint8_t i = 0; i < nOutputs; i++) - { - switch (_outputs[i].sensor_id) - { - case BSEC_OUTPUT_IAQ: - iaq = _outputs[i].signal; - iaqAccuracy = _outputs[i].accuracy; - break; - case BSEC_OUTPUT_STATIC_IAQ: - staticIaq = _outputs[i].signal; - staticIaqAccuracy = _outputs[i].accuracy; - break; - case BSEC_OUTPUT_CO2_EQUIVALENT: - co2Equivalent = _outputs[i].signal; - co2Accuracy = _outputs[i].accuracy; - break; - case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: - breathVocEquivalent = _outputs[i].signal; - breathVocAccuracy = _outputs[i].accuracy; - break; - case BSEC_OUTPUT_RAW_TEMPERATURE: - rawTemperature = _outputs[i].signal; - break; - case BSEC_OUTPUT_RAW_PRESSURE: - pressure = _outputs[i].signal; - break; - case BSEC_OUTPUT_RAW_HUMIDITY: - rawHumidity = _outputs[i].signal; - break; - case BSEC_OUTPUT_RAW_GAS: - gasResistance = _outputs[i].signal; - break; - case BSEC_OUTPUT_STABILIZATION_STATUS: - stabStatus = _outputs[i].signal; - break; - case BSEC_OUTPUT_RUN_IN_STATUS: - runInStatus = _outputs[i].signal; - break; - case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: - temperature = _outputs[i].signal; - break; - case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: - humidity = _outputs[i].signal; - break; - case BSEC_OUTPUT_COMPENSATED_GAS: - compGasValue = _outputs[i].signal; - compGasAccuracy = _outputs[i].accuracy; - break; - case BSEC_OUTPUT_GAS_PERCENTAGE: - gasPercentage = _outputs[i].signal; - gasPercentageAcccuracy = _outputs[i].accuracy; - break; - default: - break; - } - } - - return true; - } + /* sleep for 5 ms */ + delay_us(5 * 1000, _bme68x.intf_ptr); + bme68xSts = bme68x_get_op_mode(¤t_op_mode, &_bme68x); } - - return false; + return bme68xSts; } /** - * @brief Set the BME680 sensor's configuration + * @brief Function to zero the outputs */ -int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) +void Bsec::zeroOutputs(void) { - _bme680.gas_sett.run_gas = bme680Settings.run_gas; - _bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling; - _bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling; - _bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling; - _bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature; - _bme680.gas_sett.heatr_dur = bme680Settings.heating_duration; - uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | - BME680_GAS_SENSOR_SEL; - - return bme680_set_sensor_settings(desired_settings, &_bme680); + temperature = 0.0f; + pressure = 0.0f; + humidity = 0.0f; + gasResistance = 0.0f; + rawTemperature = 0.0f; + rawHumidity = 0.0f; + stabStatus = 0.0f; + runInStatus = 0.0f; + iaq = 0.0f; + iaqAccuracy = 0; + staticIaq = 0.0f; + staticIaqAccuracy = 0; + co2Equivalent = 0.0f; + co2Accuracy = 0; + breathVocEquivalent = 0.0f; + breathVocAccuracy = 0; + compGasValue = 0.0f; + compGasAccuracy = 0; + gasPercentage = 0.0f; + gasPercentageAccuracy = 0; } /** * @brief Function to zero the outputs */ -void Bsec::zeroOutputs(void) +void Bsec::zeroInputs(void) { - temperature = 0.0f; - pressure = 0.0f; - humidity = 0.0f; - gasResistance = 0.0f; - rawTemperature = 0.0f; - rawHumidity = 0.0f; - stabStatus = 0.0f; - runInStatus = 0.0f; - iaq = 0.0f; - iaqAccuracy = 0; - staticIaq = 0.0f; - staticIaqAccuracy = 0; - co2Equivalent = 0.0f; - co2Accuracy = 0; - breathVocEquivalent = 0.0f; - breathVocAccuracy = 0; - compGasValue = 0.0f; - compGasAccuracy = 0; - gasPercentage = 0.0f; - gasPercentageAcccuracy = 0; - validBsecState = false; -} + nextCall = 0; + version.major = 0; + version.minor = 0; + version.major_bugfix = 0; + version.minor_bugfix = 0; + millisOverflowCounter = 0; + lastTime = 0; + bme68xStatus = BME68X_OK; + outputTimestamp = 0; + _tempOffset = 0.0f; + bsecStatus = BSEC_OK; +} /** * @brief Function to calculate an int64_t timestamp in milliseconds */ int64_t Bsec::getTimeMs(void) { - int64_t timeMs = millis(); + int64_t timeMs = millis(); - if (lastTime > timeMs) /* An overflow occurred */ - { - millisOverflowCounter++; - } + if (lastTime > timeMs) { // An overflow occurred + millisOverflowCounter++; + } - lastTime = timeMs; + lastTime = timeMs; - return timeMs + ((int64_t)millisOverflowCounter << 32); + return timeMs + ((int64_t)millisOverflowCounter << 32); } /** - * @brief Task that delays for a ms period of time + @brief Task that delays for a us period of time */ -void Bsec::delay_ms(uint32_t period) +void Bsec::delay_us(uint32_t period, void *intfPtr) { - /* - * Wait for a period amount of ms - * The system may simply idle, sleep or even perform background tasks - */ - delay(period); + (void) intfPtr; + // Wait for a period amount of ms + // The system may simply idle, sleep or even perform background tasks + delay(period/1000); } /** - * @brief Callback function for reading registers over I2C + @brief Callback function for reading registers over I2C */ -int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) +int8_t Bsec::i2cRead(uint8_t regAddr, uint8_t *regData, uint32_t length, void *intf_ptr) { - uint16_t i; - int8_t rslt = 0; - - if (Bsec::wireObj) - { - Bsec::wireObj->beginTransmission(devId); - Bsec::wireObj->write(regAddr); - rslt = Bsec::wireObj->endTransmission(); - Bsec::wireObj->requestFrom((int) devId, (int) length); - for (i = 0; (i < length) && Bsec::wireObj->available(); i++) - { - regData[i] = Bsec::wireObj->read(); - } - } - else - { - rslt = -1; - } - - return rslt; + intptr_t devId = (intptr_t)intf_ptr; + int8_t rslt = 0; + if(Bsec::wireObj) { + Bsec::wireObj->beginTransmission(devId); + Bsec::wireObj->write(regAddr); + rslt = Bsec::wireObj->endTransmission(); + Bsec::wireObj->requestFrom((int) devId, (int) length); + for (auto i = 0; (i < length) && Bsec::wireObj->available(); i++) { + regData[i] = Bsec::wireObj->read(); + } + } else { + rslt = -1; + } + return rslt; } /** * @brief Callback function for writing registers over I2C */ -int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) +int8_t Bsec::i2cWrite(uint8_t regAddr, const uint8_t *regData, uint32_t length, void *intf_ptr) { - uint16_t i; - int8_t rslt = 0; + intptr_t devId = (intptr_t)intf_ptr; + int8_t rslt = 0; + if(Bsec::wireObj) { + Bsec::wireObj->beginTransmission(devId); + Bsec::wireObj->write(regAddr); + for (auto i = 0; i < length; i++) { + Bsec::wireObj->write(regData[i]); + } + rslt = Bsec::wireObj->endTransmission(); + } else { + rslt = -1; + } + return rslt; +} - if (Bsec::wireObj) - { - Bsec::wireObj->beginTransmission(devId); - Bsec::wireObj->write(regAddr); - for (i = 0; i < length; i++) - { - Bsec::wireObj->write(regData[i]); - } - rslt = Bsec::wireObj->endTransmission(); - } - else - { - rslt = -1; - } +/** + * @brief Callback function for reading over SPI + */ +int8_t Bsec::spiRead(uint8_t regAddr, uint8_t *regData, uint32_t length, void *intf_ptr) +{ + intptr_t devId = (intptr_t)intf_ptr; + int8_t rslt = 0; + if(Bsec::spiObj) { + Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be up to 10MHz - return rslt; + digitalWrite(devId, LOW); + + Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return + for (auto i = 0; i < length; i++) + regData[i] = Bsec::spiObj->transfer(regData[i]); + + digitalWrite(devId, HIGH); + Bsec::spiObj->endTransaction(); + } else { + rslt = -1; + } + + return rslt; } /** - * @brief Callback function for reading and writing registers over SPI + * @brief Callback function for writing registers over SPI */ -int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) +int8_t Bsec::spiWrite(uint8_t regAddr, const uint8_t *regData, uint32_t length, void *intf_ptr) { - int8_t rslt = 0; + intptr_t devId = (intptr_t)intf_ptr; + int8_t rslt = 0; + if(Bsec::spiObj) { + Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be up to 10MHz - if (Bsec::spiObj) - { - Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); /* Can be up to 10MHz */ + digitalWrite(devId, LOW); - digitalWrite(devId, LOW); + Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return + for (auto i = 0; i < length; i++) + Bsec::spiObj->transfer(regData[i]); - Bsec::spiObj->transfer(regAddr); /* Write the register address, ignore the return */ - for (uint16_t i = 0; i < length; i++) - { - regData[i] = Bsec::spiObj->transfer(regData[i]); - } + digitalWrite(devId, HIGH); + Bsec::spiObj->endTransaction(); + } else { + rslt = -1; + } - digitalWrite(devId, HIGH); - Bsec::spiObj->endTransaction(); - } - else - { - rslt = -1; - } + return rslt; +} - return rslt; -} \ No newline at end of file +/** + * @brief Function to set the Temperature, Pressure and Humidity over-sampling + */ +void Bsec::setTPH(uint8_t osTemp, uint8_t osPres, uint8_t osHum) +{ + +} diff --git a/src/bsec.h b/src/bsec.h index ca42ea9..dcf5ba1 100644 --- a/src/bsec.h +++ b/src/bsec.h @@ -29,10 +29,11 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * - * @file bsec.h - * @date 18 Nov 2020 - * + * + * @file bsec.h + * @date 27 May 2022 + * @version 1.4.1492 + * */ #ifndef BSEC_CLASS_H @@ -44,195 +45,209 @@ #include "SPI.h" #include "inc/bsec_datatypes.h" #include "inc/bsec_interface.h" -#include "bme680/bme680.h" - -/* BSEC class definition */ -class Bsec { -public: +#include "bme68x/bme68x.h" -/* Public variables */ -bsec_version_t version; /* Stores the version of the BSEC algorithm */ -int64_t nextCall; /* Stores the time when the algorithm has to be called next in ms */ -int8_t bme680Status; /* Placeholder for the BME680 driver's error codes */ -bsec_library_return_t status; -float iaq, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity, - staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage; -uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAcccuracy; -int64_t outputTimestamp; /* Timestamp in ms of the output */ -static TwoWire *wireObj; -static SPIClass *spiObj; +#define BME68X_ERROR INT8_C(-1) +#define BME68X_WARNING INT8_C(1) -/* Public APIs */ - -/** - * @brief Constructor - */ -Bsec(); - -/** - * @brief Function to initialize the BSEC library and the BME680 sensor - * @param devId : Device identifier parameter for the read/write interface functions - * @param intf : Physical communication interface - * @param read : Pointer to the read function - * @param write : Pointer to the write function - * @param idleTask : Pointer to the idling task - */ -void begin(uint8_t devId, - enum bme680_intf intf, - bme680_com_fptr_t read, - bme680_com_fptr_t write, - bme680_delay_fptr_t idleTask); - -/** - * @brief Function to initialize the BSEC library and the BME680 sensor - * @param i2cAddr : I2C address - * @param i2c : Pointer to the TwoWire object - * @param idleTask : Task to be called when idling - */ -void begin(uint8_t i2cAddr, TwoWire &i2c, bme680_delay_fptr_t idleTask = delay_ms); - -/** - * @brief Function to initialize the BSEC library and the BME680 sensor - * @param chipSelect : SPI chip select - * @param spi : Pointer to the SPIClass object - * @param idleTask : Task to be called when idling - */ -void begin(uint8_t chipSelect, SPIClass &spi, bme680_delay_fptr_t idleTask = delay_ms); - -/** - * @brief Function that sets the desired sensors and the sample rates - * @param sensorList : The list of output sensors - * @param nSensors : Number of outputs requested - * @param sampleRate : The sample rate of requested sensors - */ -void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP); - -/** - * @brief Callback from the user to trigger reading of data from the BME680, process and store outputs - * @param timeMilliseconds : Time in milliseconds. Defaults to -1 which means it takes the time from millis() - * @return true if there are new outputs. false otherwise - */ -bool run(int64_t timeMilliseconds = -1); - -/** - * @brief Function to get the state of the algorithm to save to non-volatile memory - * @param state : Pointer to a memory location that contains the state - */ -void getState(uint8_t *state); - -/** - * @brief Function to set the state of the algorithm from non-volatile memory - * @param state : Pointer to a memory location that contains the state - */ -void setState(uint8_t *state); - -/** - * @brief Function to set the configuration of the algorithm from memory - * @param state : Pointer to a memory location that contains the configuration - */ -void setConfig(const uint8_t *config); - -/** - * @brief Function to set the temperature offset - * @param tempOffset : Temperature offset in degree Celsius - */ -void setTemperatureOffset(float tempOffset) +/* BSEC class definition */ +class Bsec { - _tempOffset = tempOffset; -} - -/** - * @brief Function to calculate an int64_t timestamp in milliseconds - */ -int64_t getTimeMs(void); - -/** - * @brief Task that delays for a ms period of time - * @param period : Period of time in ms - */ -static void delay_ms(uint32_t period); - -/** - * @brief Callback function for reading registers over I2C - * @param devId : Library agnostic parameter to identify the device to communicate with - * @param regAddr : Register address - * @param regData : Pointer to the array containing the data to be read - * @param length : Length of the array of data - * @return Zero for success, non-zero otherwise - */ -static int8_t i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); - -/** - * @brief Callback function for writing registers over I2C - * @param devId : Library agnostic parameter to identify the device to communicate with - * @param regAddr : Register address - * @param regData : Pointer to the array containing the data to be written - * @param length : Length of the array of data - * @return Zero for success, non-zero otherwise - */ -static int8_t i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); - -/** - * @brief Callback function for reading and writing registers over SPI - * @param devId : Library agnostic parameter to identify the device to communicate with - * @param regAddr : Register address - * @param regData : Pointer to the array containing the data to be read or written - * @param length : Length of the array of data - * @return Zero for success, non-zero otherwise - */ -static int8_t spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); - +public: + /* Public variables */ + bsec_version_t version; // Stores the version of the BSEC algorithm + int64_t nextCall; // Stores the time when the algorithm has to be called next in ms + int8_t bme68xStatus; // Placeholder for the BME68x driver's error codes + bsec_library_return_t bsecStatus; + float iaq, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity, + staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage; + uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAccuracy; + int64_t outputTimestamp; // Timestamp in ms of the output + static TwoWire *wireObj; + static SPIClass *spiObj; + struct bme68x_conf conf; + struct bme68x_heatr_conf heatrConf; + + + /* Public APIs */ + /** + * @brief Constructor + */ + Bsec(); + + /** + * @brief Function to initialize the BSEC library and the BME68x sensor + * @param intf : BME68X_SPI_INTF or BME68X_I2C_INTF interface + * @param read : Read callback + * @param write : Write callback + * @param idleTask : Delay or Idle function + * @param intfPtr : Pointer to the interface descriptor + */ + void begin(bme68x_intf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write, bme68x_delay_us_fptr_t idleTask, void *intfPtr); + + /** + * @brief Function to initialize the BSEC library and the BME68x sensor + * @param i2cAddr : I2C address + * @param i2c : Pointer to the TwoWire object + */ + void begin(uint8_t i2cAddr, TwoWire &i2c); + + /** + * @brief Function to initialize the BSEC library and the BME68x sensor + * @param chipSelect : SPI chip select + * @param spi : Pointer to the SPIClass object + */ + void begin(uint8_t chipSelect, SPIClass &spi); + + /** + * @brief Function that sets the desired sensors and the sample rates + * @param sensorList : The list of output sensors + * @param nSensors : Number of outputs requested + * @param sampleRate : The sample rate of requested sensors + */ + void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP); + + /** + * @brief Callback from the user to trigger reading of data from the BME68x, process and store outputs + * @return true if there are new outputs. false otherwise + */ + bool run(void); + + /** + * @brief Function to get the state of the algorithm to save to non-volatile memory + * @param state : Pointer to a memory location that contains the state + */ + void getState(uint8_t *state); + + /** + * @brief Function to set the state of the algorithm from non-volatile memory + * @param state : Pointer to a memory location that contains the state + */ + void setState(uint8_t *state); + + /** + * @brief Function to set the configuration of the algorithm from memory + * @param state : Pointer to a memory location that contains the configuration + */ + void setConfig(const uint8_t *config); + + /** + * @brief Function to set the temperature offset + * @param tempOffset : Temperature offset in degree Celsius + */ + void setTemperatureOffset(float tempOffset) + { + _tempOffset = tempOffset; + } + + + /** + * @brief Function to calculate an int64_t timestamp in milliseconds + */ + int64_t getTimeMs(void); + + /** + * @brief Task that delays for a ms period of time + * @param period : Period of time in us + * @param intfPtr: Pointer to the interface descriptor + */ + static void delay_us(uint32_t period, void *intfPtr); + + /** + * @brief Callback function for reading registers over I2C + * @param regAddr : Register address of the sensor + * @param regData : Pointer to the data to be written to the sensor + * @param length : Length of the transfer + * @param intfPtr : Pointer to the interface descriptor + * @return Zero for success, non-zero otherwise + */ + static int8_t i2cRead(uint8_t regAddr, uint8_t *regData, uint32_t length, void *intfPtr); + + /** + * @brief Callback function for writing registers over I2C + * @param regAddr : Register address of the sensor + * @param regData : Pointer to the data to be written to the sensor + * @param length : Length of the transfer + * @param intfPtr : Pointer to the interface descriptor + * @return Zero for success, non-zero otherwise + */ + static int8_t i2cWrite(uint8_t regAddr, const uint8_t *regData, uint32_t length, void *intfPtr); + + /** + * @brief Function that implements the default SPI read transaction + * @param regAddr : Register address of the sensor + * @param regData : Pointer to the data to be read from the sensor + * @param length : Length of the transfer + * @param intfPtr : Pointer to the interface descriptor + * @return 0 if successful, non-zero otherwise + */ + static int8_t spiRead(uint8_t regAddr, uint8_t *regData, uint32_t length, void *intfPtr); + + /** + * @brief Function that implements the default SPI write transaction + * @param regAddr : Register address of the sensor + * @param regData : Pointer to the data to be written to the sensor + * @param length : Length of the transfer + * @param intfPtr : Pointer to the interface descriptor + * @return 0 if successful, non-zero otherwise + */ + static int8_t spiWrite(uint8_t regAddr, const uint8_t *regData, uint32_t length, void *intfPtr); + + /** + * @brief Function to set the Temperature, Pressure and Humidity over-sampling. + * Passing no arguments sets the defaults. + * @param osTemp : BME68X_OS_NONE to BME68X_OS_16X + * @param osPres : BME68X_OS_NONE to BME68X_OS_16X + * @param osHum : BME68X_OS_NONE to BME68X_OS_16X + */ + void setTPH(uint8_t osTemp = BME68X_OS_2X, uint8_t osPres = BME68X_OS_16X, uint8_t osHum = BME68X_OS_1X); + private: - -/* Private variables */ -struct bme680_dev _bme680; -struct bme680_field_data _data; -float _tempOffset; -/* - * Global variables to help create a millisecond timestamp that doesn't overflow every 51 days. - * If it overflows, it will have a negative value. Something that should never happen. - */ -uint32_t millisOverflowCounter; -uint32_t lastTime; - -uint8_t *bsecConfig; -bool validBsecState; -uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE]; -bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS], sensorSettings[BSEC_MAX_PHYSICAL_SENSOR]; -uint8_t nSensorSettings; - -/* Private APIs */ - -/** - * @brief Get the version of the BSEC library - */ -void getVersion(void); - -/** - * @brief Read data from the BME680 and process it - * @param currTimeNs: Current time in ns - * @param bme680Settings: BME680 sensor's settings - * @return true if there are new outputs. false otherwise - */ -bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings); - -/** - * @brief Set the BME680 sensor's configuration - * @param bme680Settings: Settings to configure the BME680 - * @return BME680 return code. BME680_OK for success, failure otherwise - */ -int8_t setBme680Config(bsec_bme_settings_t bme680Settings); - -/** - * @brief Common code for the begin function - */ -void beginCommon(void); - -/** - * @brief Function to zero the outputs - */ -void zeroOutputs(void); - + /* Private variables */ + struct bme68x_dev _bme68x; + struct bme68x_data _data; + float _tempOffset; + // Global variables to help create a millisecond timestamp that doesn't overflow every 51 days. + // If it overflows, it will have a negative value. Something that should never happen. + uint32_t millisOverflowCounter; + uint32_t lastTime; + uint8_t nFields; + + /* Private APIs */ + /** + * @brief Get the version of the BSEC library + */ + void getVersion(void); + + /** + * @brief Read data from the BME68x and process it + * @param currTimeNs: Current time in ns + * @param bme68xSettings: BME68x sensor's settings + * @return true if there are new outputs. false otherwise + */ + bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme68xSettings); + + /** + * @brief Set the BME68x sensor's configuration + * @param bme68xSettings: Settings to configure the BME68x sensor + * @return BME68x return code. BME68X_OK for success, failure otherwise + */ + int8_t setBme68xConfig(bsec_bme_settings_t bme68xSettings); + + /** + * @brief Common code for the begin function + */ + void beginCommon(void); + + /** + * @brief Function to zero the outputs + */ + void zeroOutputs(void); + + /** + * @brief Function to zero the inputs + */ + void zeroInputs(void); }; #endif diff --git a/src/config/generic_18v_300s_28d/bsec_iaq.txt b/src/config/generic_18v_300s_28d/bsec_iaq.txt index 3897582..30603e7 100644 --- a/src/config/generic_18v_300s_28d/bsec_iaq.txt +++ b/src/config/generic_18v_300s_28d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,226,227,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,168,19,73,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,254,131,137,87,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,98,60,0,0 \ No newline at end of file diff --git a/src/config/generic_18v_300s_4d/bsec_iaq.txt b/src/config/generic_18v_300s_4d/bsec_iaq.txt index 2e068d7..6bfcd97 100644 --- a/src/config/generic_18v_300s_4d/bsec_iaq.txt +++ b/src/config/generic_18v_300s_4d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,193,132,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,192,168,71,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,35,41,29,86,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,179,77,0,0 \ No newline at end of file diff --git a/src/config/generic_18v_3s_28d/bsec_iaq.txt b/src/config/generic_18v_3s_28d/bsec_iaq.txt index 92e4903..7e2819d 100644 --- a/src/config/generic_18v_3s_28d/bsec_iaq.txt +++ b/src/config/generic_18v_3s_28d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,112,234,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,168,19,73,64,49,119,76,0,192,40,72,0,192,40,72,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,254,131,137,87,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,226,221,0,0 \ No newline at end of file diff --git a/src/config/generic_18v_3s_4d/bsec_iaq.txt b/src/config/generic_18v_3s_4d/bsec_iaq.txt index 778958e..cd231d5 100644 --- a/src/config/generic_18v_3s_4d/bsec_iaq.txt +++ b/src/config/generic_18v_3s_4d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,83,141,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,192,168,71,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,35,41,29,86,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,33,68,0,0 \ No newline at end of file diff --git a/src/config/generic_33v_300s_28d/bsec_iaq.txt b/src/config/generic_33v_300s_28d/bsec_iaq.txt index c657143..2024999 100644 --- a/src/config/generic_33v_300s_28d/bsec_iaq.txt +++ b/src/config/generic_33v_300s_28d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,92,90,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,168,19,73,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,254,131,137,87,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,220,133,0,0 \ No newline at end of file diff --git a/src/config/generic_33v_300s_4d/bsec_iaq.txt b/src/config/generic_33v_300s_4d/bsec_iaq.txt index 34071f5..c182ce7 100644 --- a/src/config/generic_33v_300s_4d/bsec_iaq.txt +++ b/src/config/generic_33v_300s_4d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,127,61,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,192,168,71,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,35,41,29,86,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,13,244,0,0 \ No newline at end of file diff --git a/src/config/generic_33v_3s_28d/bsec_iaq.txt b/src/config/generic_33v_3s_28d/bsec_iaq.txt index 772fd36..b077fd1 100644 --- a/src/config/generic_33v_3s_28d/bsec_iaq.txt +++ b/src/config/generic_33v_3s_28d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,206,83,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,168,19,73,64,49,119,76,0,192,40,72,0,192,40,72,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,254,131,137,87,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,92,100,0,0 \ No newline at end of file diff --git a/src/config/generic_33v_3s_4d/bsec_iaq.txt b/src/config/generic_33v_3s_4d/bsec_iaq.txt index 06e857b..7aae2d8 100644 --- a/src/config/generic_33v_3s_4d/bsec_iaq.txt +++ b/src/config/generic_33v_3s_4d/bsec_iaq.txt @@ -1 +1 @@ -0,8,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,237,52,0,0 +2,9,4,1,61,0,0,0,0,0,0,0,182,1,0,0,52,0,1,0,0,192,168,71,64,49,119,76,0,0,97,69,0,0,97,69,137,65,0,191,205,204,204,190,0,0,64,191,225,122,148,190,10,0,3,0,216,85,0,100,0,0,96,64,23,183,209,56,28,0,2,0,0,244,1,150,0,50,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,13,0,5,0,0,0,0,0,1,35,41,29,86,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,159,253,0,0 \ No newline at end of file diff --git a/src/cortex-m0/libalgobsec.a b/src/cortex-m0/libalgobsec.a index 5b19c96..df65526 100644 Binary files a/src/cortex-m0/libalgobsec.a and b/src/cortex-m0/libalgobsec.a differ diff --git a/src/cortex-m0plus/libalgobsec.a b/src/cortex-m0plus/libalgobsec.a index 6bb9806..52a454d 100644 Binary files a/src/cortex-m0plus/libalgobsec.a and b/src/cortex-m0plus/libalgobsec.a differ diff --git a/src/cortex-m3/libalgobsec.a b/src/cortex-m3/libalgobsec.a index 51c6242..397c951 100644 Binary files a/src/cortex-m3/libalgobsec.a and b/src/cortex-m3/libalgobsec.a differ diff --git a/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a b/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a index 0650d86..61465d2 100644 Binary files a/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a and b/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a differ diff --git a/src/cortex-m4/libalgobsec.a b/src/cortex-m4/libalgobsec.a index 4168f85..8068cd6 100644 Binary files a/src/cortex-m4/libalgobsec.a and b/src/cortex-m4/libalgobsec.a differ diff --git a/src/esp32/libalgobsec.a b/src/esp32/libalgobsec.a index 0815f73..729fdf9 100644 Binary files a/src/esp32/libalgobsec.a and b/src/esp32/libalgobsec.a differ diff --git a/src/esp8266/libalgobsec.a b/src/esp8266/libalgobsec.a index 9e61c81..18972df 100644 Binary files a/src/esp8266/libalgobsec.a and b/src/esp8266/libalgobsec.a differ diff --git a/src/inc/bsec_datatypes.h b/src/inc/bsec_datatypes.h index 7cf1201..ed7566f 100644 --- a/src/inc/bsec_datatypes.h +++ b/src/inc/bsec_datatypes.h @@ -86,11 +86,11 @@ extern "C" #define BSEC_MAX_WORKBUFFER_SIZE (2048) /*!< Maximum size (in bytes) of the work buffer */ #define BSEC_MAX_PHYSICAL_SENSOR (8) /*!< Number of physical sensors that need allocated space before calling bsec_update_subscription() */ -#define BSEC_MAX_PROPERTY_BLOB_SIZE (454) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_configuration() */ -#define BSEC_MAX_STATE_BLOB_SIZE (139) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_state()*/ +#define BSEC_MAX_PROPERTY_BLOB_SIZE (462) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_configuration() */ +#define BSEC_MAX_STATE_BLOB_SIZE (155) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_state()*/ #define BSEC_SAMPLE_RATE_DISABLED (65535.0f) /*!< Sample rate of a disabled sensor */ #define BSEC_SAMPLE_RATE_ULP (0.0033333f) /*!< Sample rate in case of Ultra Low Power Mode */ -#define BSEC_SAMPLE_RATE_CONTINUOUS (1.0f) /*!< Sample rate in case of Continuous Mode */ +#define BSEC_SAMPLE_RATE_CONT (1.0f) /*!< Sample rate in case of Continuous Mode */ #define BSEC_SAMPLE_RATE_LP (0.33333f) /*!< Sample rate in case of Low Power Mode */ #define BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND (0.0f) /*!< Input value used to trigger an extra measurment (ULP plus) */ @@ -156,18 +156,13 @@ typedef enum */ BSEC_INPUT_HEATSOURCE = 14, - /** - * @brief Additional input for device heat compensation 8 - * - * Generic heat source 8 - */ - + /** * @brief Additional input that disables baseline tracker * - * 0 - Normal - * 1 - Event 1 + * 0 - Normal, + * 1 - Event 1, * 2 - Event 2 */ BSEC_INPUT_DISABLE_BASELINE_TRACKER = 23, @@ -185,20 +180,20 @@ typedef enum typedef enum { /** - * @brief Indoor-air-quality estimate [0-500] + * @brief Index for Air Quality estimate [0-500] * - * Indoor-air-quality (IAQ) gives an indication of the relative change in ambient TVOCs detected by BME680. + * Index for Air Quality (IAQ) gives an indication of the relative change in ambient TVOCs detected by BME680. * * @note The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air). During operation, algorithms * automatically calibrate and adapt themselves to the typical environments where the sensor is operated * (e.g., home, workplace, inside a car, etc.).This automatic background calibration ensures that users experience * consistent IAQ performance. The calibration process considers the recent measurement history (typ. up to four - * days) to ensure that IAQ=25 corresponds to typical good air and IAQ=250 indicates typical polluted air. + * days) to ensure that IAQ=50 corresponds to typical good air and IAQ=200 indicates typical polluted air. */ BSEC_OUTPUT_IAQ = 1, - BSEC_OUTPUT_STATIC_IAQ = 2, /*!< Unscaled indoor-air-quality estimate */ - BSEC_OUTPUT_CO2_EQUIVALENT = 3, /*!< co2 equivalent estimate [ppm] */ - BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, /*!< breath VOC concentration estimate [ppm] */ + BSEC_OUTPUT_STATIC_IAQ = 2, /*!< Unscaled Index for Air Quality estimate */ + BSEC_OUTPUT_CO2_EQUIVALENT = 3, /*!< CO2 equivalent estimate [ppm] */ + BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, /*!< Breath VOC concentration estimate [ppm] */ /** * @brief Temperature sensor signal [degrees Celsius] @@ -261,10 +256,10 @@ typedef enum * * Thus, the value is calculated as follows: * * IAQ solution: ```BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage) - ::BSEC_INPUT_HEATSOURCE``` - * * other solutions: ```::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage)``` + * * Other solutions: ```::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage)``` * - * The self-heating in operation mode BSEC_SAMPLE_RATE_ULP is negligible. - * The self-heating in operation mode BSEC_SAMPLE_RATE_LP is supported for 1.8V by default (no config file required). If the BME680 sensor supply voltage is 3.3V, the IoT_LP_3_3V.config shall be used. + * The self-heating in operation mode #BSEC_SAMPLE_RATE_ULP is negligible. + * The self-heating in operation mode #BSEC_SAMPLE_RATE_LP is supported for 1.8V by default (no config file required). If the BME680 sensor supply voltage is 3.3V, the corresponding config file shall be used. */ BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14, @@ -281,8 +276,7 @@ typedef enum */ BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15, - BSEC_OUTPUT_COMPENSATED_GAS = 18, /*!< Reserved internal debug output */ - BSEC_OUTPUT_GAS_PERCENTAGE = 21 /*!< percentage of min and max filtered gas value [%] */ + BSEC_OUTPUT_GAS_PERCENTAGE = 21 /*!< Percentage of min and max filtered gas value [%] */ } bsec_virtual_sensor_t; /*! @@ -293,10 +287,10 @@ typedef enum BSEC_OK = 0, /*!< Function execution successful */ BSEC_E_DOSTEPS_INVALIDINPUT = -1, /*!< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */ BSEC_E_DOSTEPS_VALUELIMITS = -2, /*!< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */ + BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4, /*!< Past timestamps passed to bsec_do_steps() */ BSEC_E_DOSTEPS_DUPLICATEINPUT = -6, /*!< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */ BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2, /*!< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */ BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3, /*!< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */ - BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4, /*!< Duplicate timestamps passed to bsec_do_steps() */ BSEC_E_SU_WRONGDATARATE = -10, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */ BSEC_E_SU_SAMPLERATELIMITS = -12, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */ BSEC_E_SU_DUPLICATEGATE = -13, /*!< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */ @@ -397,15 +391,6 @@ typedef struct * * For example: * - * - Ambient temperature accuracy is derived from change in the temperature in 1 minute. - * - * | Virtual sensor | Value | Accuracy description | - * |--------------------- |-------|------------------------------------------------------------------------------| - * | Ambient temperature | 0 | The difference in ambient temperature is greater than 4 degree in one minute | - * | | 1 | The difference in ambient temperature is less than 4 degree in one minute | - * | | 2 | The difference in ambient temperature is less than 3 degree in one minute | - * | | 3 | The difference in ambient temperature is less than 2 degree in one minute | - * * - IAQ accuracy indicator will notify the user when she/he should initiate a calibration process. Calibration is * performed automatically in the background if the sensor is exposed to clean and polluted air for approximately * 30 minutes each. @@ -467,7 +452,7 @@ typedef struct typedef struct { int64_t next_call; /*!< @brief Time stamp of the next call of the sensor_control*/ - uint32_t process_data; /*!< @brief Bit field describing which data is to be passed to bsec_do_steps() @sa BSEC_PROCESS_* */ + uint32_t process_data; /*!< @brief Bit field describing which data is to be passed to bsec_do_steps() @sa BSEC_PROCESS_GAS, BSEC_PROCESS_TEMPERATURE, BSEC_PROCESS_HUMIDITY, BSEC_PROCESS_PRESSURE */ uint16_t heater_temperature; /*!< @brief Heating temperature [degrees Celsius] */ uint16_t heating_duration; /*!< @brief Heating duration [ms] */ uint8_t run_gas; /*!< @brief Enable gas measurements [0/1] */ diff --git a/src/inc/bsec_interface.h b/src/inc/bsec_interface.h index a3c1da5..7f400b7 100644 --- a/src/inc/bsec_interface.h +++ b/src/inc/bsec_interface.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential. * * Disclaimer @@ -56,10 +56,7 @@ * It is not allowed to deliver the source code of the Software to any third party without permission of * Bosch Sensortec. * - */ - /*! - * - * @file bsec_interface.h + * @file bsec_interface.h * * @brief * Contains the API for BSEC @@ -105,18 +102,18 @@ * | Steps | Function | * |-------------------------------------------|----------------------------------| * | Retrieve sensor settings to be used | bsec_sensor_control() | - * | Configure sensor and trigger measurement | See BME680 API and example codes | - * | Read results from sensor | See BME680 API and example codes | + * | Configure sensor and trigger measurement | [See BME680 API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) | + * | Read results from sensor | [See BME680 API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) | * | Perform signal processing | bsec_do_steps() | * * * - Before shutting down the system, the current state of BSEC can be retrieved and can then be used during * re-initialization to continue processing. * - * | Steps | Function | - * |----------------------------------------|-------------------| - * | To retrieve the current library state | bsec_get_state() | - * + * | Steps | Function | + * |---------------------------------------------|-------------------| + * | Retrieve the current library state | bsec_get_state() | + * | Retrieve the current library configuration | bsec_get_configuration() | * * * ### Configuration and state @@ -188,7 +185,7 @@ bsec_library_return_t bsec_init(void); * * Based on the requested virtual sensors outputs, BSEC will provide information about the required physical sensor input signals * (see ::bsec_physical_sensor_t) with corresponding sample rates. This information is purely informational as bsec_sensor_control() - * will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to BSEC_SAMPLE_RATE_DISABLED. + * will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to #BSEC_SAMPLE_RATE_DISABLED. * * The subscription update using bsec_update_subscription() is apart from the signal processing one of the the most * important functions. It allows to enable the desired library outputs. The function determines which physical input @@ -207,7 +204,7 @@ bsec_library_return_t bsec_init(void); * - Identifiers are unique values defined by the library, not from external * - Sample rates must be provided as value of * - An allowed sample rate for continuously sampled signals - * - 65535.0f (BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs + * - 65535.0f (#BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs * * @note The same sensor identifiers are also used within the functions bsec_do_steps(). * @@ -330,8 +327,8 @@ bsec_library_return_t bsec_update_subscription(const bsec_sensor_configuration_t // Retrieve the IAQ results from output[i].signal // and do something with the data break; - case BSEC_OUTPUT_AMBIENT_TEMPERATURE: - // Retrieve the ambient temperature results from output[i].signal + case BSEC_OUTPUT_STATIC_IAQ: + // Retrieve the static IAQ results from output[i].signal // and do something with the data break; @@ -373,8 +370,9 @@ bsec_library_return_t bsec_reset_output(uint8_t sensor_id); * by bsec_set_configuration(). This is an optional step. * * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose - * the serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting - * the required size. + * the serialization and apply it to the library and its modules. + * + * Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size. * * @param[in] serialized_settings Settings serialized to a binary blob * @param[in] n_serialized_settings Size of the settings blob @@ -389,8 +387,8 @@ bsec_library_return_t bsec_reset_output(uint8_t sensor_id); // Allocate variables uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE]; uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE; - uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; - uint32_t n_work_buffer = BSEC_MAX_PROPERTY_BLOB_SIZE; + uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE]; + uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE; // Here we will load a provided config string into serialized_settings @@ -414,8 +412,9 @@ bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_se * before resuming further operation of the library. * * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the - * serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the - * required size. + * serialization and apply it to the library and its modules. + * + * Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size. * * @param[in] serialized_state States serialized to a binary blob * @param[in] n_serialized_state Size of the state blob @@ -430,8 +429,8 @@ bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_se // Allocate variables uint8_t serialized_state[BSEC_MAX_PROPERTY_BLOB_SIZE]; uint32_t n_serialized_state = BSEC_MAX_PROPERTY_BLOB_SIZE; - uint8_t work_buffer_state[BSEC_MAX_PROPERTY_BLOB_SIZE]; - uint32_t n_work_buffer_size = BSEC_MAX_PROPERTY_BLOB_SIZE; + uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE]; + uint32_t n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE; // Here we will load a state string from a previous use of BSEC @@ -453,10 +452,10 @@ bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, con * * @note The function bsec_get_configuration() is required to be used for debugging purposes only. * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the - * serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the - * required size. - * + * serialization and apply it to the library and its modules. * + * Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size. + * * @param[in] config_id Identifier for a specific set of configuration settings to be returned; * shall be zero to retrieve all configuration settings. * @param[out] serialized_settings Buffer to hold the serialized config blob @@ -473,8 +472,8 @@ bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, con // Allocate variables uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE]; uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE; - uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; - uint32_t n_work_buffer = BSEC_MAX_PROPERTY_BLOB_SIZE; + uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE]; + uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE; uint32_t n_serialized_settings = 0; // Configuration of BSEC algorithm is stored in 'serialized_settings' @@ -494,10 +493,10 @@ bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * * bsec_get_state(). This allows a restart of the processing after a reboot of the system by calling bsec_set_state(). * * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the - * serialization and apply it to the library and its modules. Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the - * required size. - * + * serialization and apply it to the library and its modules. * + * Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size. + * * @param[in] state_set_id Identifier for a specific set of states to be returned; shall be * zero to retrieve all states. * @param[out] serialized_state Buffer to hold the serialized config blob @@ -515,8 +514,8 @@ bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE]; uint32_t n_serialized_state_max = BSEC_MAX_STATE_BLOB_SIZE; uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE; - uint8_t work_buffer_state[BSEC_MAX_STATE_BLOB_SIZE]; - uint32_t n_work_buffer_size = BSEC_MAX_STATE_BLOB_SIZE; + uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE]; + uint32_t n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE; // Algorithm state is stored in 'serialized_state' bsec_get_state(0, serialized_state, n_serialized_state_max, work_buffer_state, n_work_buffer_size, &n_serialized_state);