commit
e37c8ba732
@ -5,6 +5,8 @@
|
|||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include "bsec_integration.h"
|
#include "bsec_integration.h"
|
||||||
|
|
||||||
|
extern const uint8_t bsec_config_iaq[454];
|
||||||
|
|
||||||
extern bmeStatus_t
|
extern bmeStatus_t
|
||||||
bme_status; // Make struct for storing gps data globally available
|
bme_status; // Make struct for storing gps data globally available
|
||||||
extern TaskHandle_t BmeTask;
|
extern TaskHandle_t BmeTask;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#define LPP_MSG_CHANNEL 28
|
#define LPP_MSG_CHANNEL 28
|
||||||
#define LPP_HUMIDITY_CHANNEL 29
|
#define LPP_HUMIDITY_CHANNEL 29
|
||||||
#define LPP_BAROMETER_CHANNEL 30
|
#define LPP_BAROMETER_CHANNEL 30
|
||||||
#define LPP_GAS_CHANNEL 31
|
#define LPP_AIR_CHANNEL 31
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -66,8 +66,9 @@ private:
|
|||||||
void writeUint32(uint32_t i);
|
void writeUint32(uint32_t i);
|
||||||
void writeUint16(uint16_t i);
|
void writeUint16(uint16_t i);
|
||||||
void writeUint8(uint8_t i);
|
void writeUint8(uint8_t i);
|
||||||
void writeHumidity(float humidity);
|
void writeFloat(float value);
|
||||||
void writeTemperature(float temperature);
|
void writeUFloat(float value);
|
||||||
|
void writePressure(float value);
|
||||||
void writeVersion(char * version);
|
void writeVersion(char * version);
|
||||||
void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g,
|
void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g,
|
||||||
bool h);
|
bool h);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include "bsec_serialized_configurations_iaq.h"
|
#include "bsec_serialized_configurations_iaq.h"
|
||||||
|
|
||||||
|
|
||||||
const uint8_t bsec_config_iaq[454] =
|
const uint8_t bsec_config_iaq[454] =
|
||||||
{1,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,225,68,0,192,168,71,64,49,119,76,0,0,0,0,0,80,5,95,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,239,79,0,0};
|
{1,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,225,68,0,192,168,71,64,49,119,76,0,0,0,0,0,80,5,95,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,239,79,0,0};
|
||||||
|
|
||||||
|
Binary file not shown.
@ -1,559 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_integration.c
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Private part of the example for using of BSEC library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "bsec_integration.h"
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* local macro definitions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
#define NUM_USED_OUTPUTS 8
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* global variable declarations */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/* Global sensor APIs data structure */
|
|
||||||
static struct bme680_dev bme680_g;
|
|
||||||
|
|
||||||
/* Global temperature offset to be subtracted */
|
|
||||||
static float bme680_temperature_offset_g = 0.0f;
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* functions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Virtual sensor subscription
|
|
||||||
* Please call this function before processing of data using bsec_do_steps function
|
|
||||||
*
|
|
||||||
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
|
|
||||||
*
|
|
||||||
* @return subscription result, zero when successful
|
|
||||||
*/
|
|
||||||
static bsec_library_return_t bme680_bsec_update_subscription(float sample_rate)
|
|
||||||
{
|
|
||||||
bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS];
|
|
||||||
uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS;
|
|
||||||
|
|
||||||
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
|
|
||||||
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
|
|
||||||
|
|
||||||
bsec_library_return_t status = BSEC_OK;
|
|
||||||
|
|
||||||
/* note: Virtual sensors as desired to be added here */
|
|
||||||
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
|
|
||||||
requested_virtual_sensors[0].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
|
|
||||||
requested_virtual_sensors[1].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
|
|
||||||
requested_virtual_sensors[2].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
|
|
||||||
requested_virtual_sensors[3].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_RAW_GAS;
|
|
||||||
requested_virtual_sensors[4].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
|
|
||||||
requested_virtual_sensors[5].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
|
|
||||||
requested_virtual_sensors[6].sample_rate = sample_rate;
|
|
||||||
requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
|
|
||||||
requested_virtual_sensors[7].sample_rate = sample_rate;
|
|
||||||
|
|
||||||
/* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
|
|
||||||
status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
|
|
||||||
&n_required_sensor_settings);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Initialize the BME680 sensor and the BSEC library
|
|
||||||
*
|
|
||||||
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
|
|
||||||
* @param[in] temperature_offset device-specific temperature offset (due to self-heating)
|
|
||||||
* @param[in] bus_write pointer to the bus writing function
|
|
||||||
* @param[in] bus_read pointer to the bus reading function
|
|
||||||
* @param[in] sleep pointer to the system specific sleep function
|
|
||||||
* @param[in] state_load pointer to the system-specific state load function
|
|
||||||
* @param[in] config_load pointer to the system-specific config load function
|
|
||||||
*
|
|
||||||
* @return zero if successful, negative otherwise
|
|
||||||
*/
|
|
||||||
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write,
|
|
||||||
bme680_com_fptr_t bus_read, sleep_fct sleep, state_load_fct state_load, config_load_fct config_load)
|
|
||||||
{
|
|
||||||
return_values_init ret = {BME680_OK, BSEC_OK};
|
|
||||||
bsec_library_return_t bsec_status = BSEC_OK;
|
|
||||||
|
|
||||||
uint8_t bsec_state[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
|
|
||||||
uint8_t bsec_config[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
|
|
||||||
uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
|
|
||||||
int bsec_state_len, bsec_config_len;
|
|
||||||
|
|
||||||
/* Fixed I2C configuration */
|
|
||||||
bme680_g.dev_id = BME680_I2C_ADDR_PRIMARY;
|
|
||||||
bme680_g.intf = BME680_I2C_INTF;
|
|
||||||
/* User configurable I2C configuration */
|
|
||||||
bme680_g.write = bus_write;
|
|
||||||
bme680_g.read = bus_read;
|
|
||||||
bme680_g.delay_ms = sleep;
|
|
||||||
|
|
||||||
/* Initialize BME680 API */
|
|
||||||
ret.bme680_status = bme680_init(&bme680_g);
|
|
||||||
if (ret.bme680_status != BME680_OK)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize BSEC library */
|
|
||||||
ret.bsec_status = bsec_init();
|
|
||||||
if (ret.bsec_status != BSEC_OK)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load library config, if available */
|
|
||||||
bsec_config_len = config_load(bsec_config, sizeof(bsec_config));
|
|
||||||
if (bsec_config_len != 0)
|
|
||||||
{
|
|
||||||
ret.bsec_status = bsec_set_configuration(bsec_config, bsec_config_len, work_buffer, sizeof(work_buffer));
|
|
||||||
if (ret.bsec_status != BSEC_OK)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load previous library state, if available */
|
|
||||||
bsec_state_len = state_load(bsec_state, sizeof(bsec_state));
|
|
||||||
if (bsec_state_len != 0)
|
|
||||||
{
|
|
||||||
ret.bsec_status = bsec_set_state(bsec_state, bsec_state_len, work_buffer, sizeof(work_buffer));
|
|
||||||
if (ret.bsec_status != BSEC_OK)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set temperature offset */
|
|
||||||
bme680_temperature_offset_g = temperature_offset;
|
|
||||||
|
|
||||||
/* Call to the function which sets the library with subscription information */
|
|
||||||
ret.bsec_status = bme680_bsec_update_subscription(sample_rate);
|
|
||||||
if (ret.bsec_status != BSEC_OK)
|
|
||||||
{
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Trigger the measurement based on sensor settings
|
|
||||||
*
|
|
||||||
* @param[in] sensor_settings settings of the BME680 sensor adopted by sensor control function
|
|
||||||
* @param[in] sleep pointer to the system specific sleep function
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void bme680_bsec_trigger_measurement(bsec_bme_settings_t *sensor_settings, sleep_fct sleep)
|
|
||||||
{
|
|
||||||
uint16_t meas_period;
|
|
||||||
uint8_t set_required_settings;
|
|
||||||
int8_t bme680_status = BME680_OK;
|
|
||||||
|
|
||||||
/* Check if a forced-mode measurement should be triggered now */
|
|
||||||
if (sensor_settings->trigger_measurement)
|
|
||||||
{
|
|
||||||
/* Set sensor configuration */
|
|
||||||
|
|
||||||
bme680_g.tph_sett.os_hum = sensor_settings->humidity_oversampling;
|
|
||||||
bme680_g.tph_sett.os_pres = sensor_settings->pressure_oversampling;
|
|
||||||
bme680_g.tph_sett.os_temp = sensor_settings->temperature_oversampling;
|
|
||||||
bme680_g.gas_sett.run_gas = sensor_settings->run_gas;
|
|
||||||
bme680_g.gas_sett.heatr_temp = sensor_settings->heater_temperature; /* degree Celsius */
|
|
||||||
bme680_g.gas_sett.heatr_dur = sensor_settings->heating_duration; /* milliseconds */
|
|
||||||
|
|
||||||
/* Select the power mode */
|
|
||||||
/* Must be set before writing the sensor configuration */
|
|
||||||
bme680_g.power_mode = BME680_FORCED_MODE;
|
|
||||||
/* Set the required sensor settings needed */
|
|
||||||
set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;
|
|
||||||
|
|
||||||
/* Set the desired sensor configuration */
|
|
||||||
bme680_status = bme680_set_sensor_settings(set_required_settings, &bme680_g);
|
|
||||||
|
|
||||||
/* Set power mode as forced mode and trigger forced mode measurement */
|
|
||||||
bme680_status = bme680_set_sensor_mode(&bme680_g);
|
|
||||||
|
|
||||||
/* Get the total measurement duration so as to sleep or wait till the measurement is complete */
|
|
||||||
bme680_get_profile_dur(&meas_period, &bme680_g);
|
|
||||||
|
|
||||||
/* Delay till the measurement is ready. Timestamp resolution in ms */
|
|
||||||
sleep((uint32_t)meas_period);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the API to get current operation mode of the sensor */
|
|
||||||
bme680_status = bme680_get_sensor_mode(&bme680_g);
|
|
||||||
/* When the measurement is completed and data is ready for reading, the sensor must be in BME680_SLEEP_MODE.
|
|
||||||
* Read operation mode to check whether measurement is completely done and wait until the sensor is no more
|
|
||||||
* in BME680_FORCED_MODE. */
|
|
||||||
while (bme680_g.power_mode == BME680_FORCED_MODE)
|
|
||||||
{
|
|
||||||
/* sleep for 5 ms */
|
|
||||||
sleep(5);
|
|
||||||
bme680_status = bme680_get_sensor_mode(&bme680_g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Read the data from registers and populate the inputs structure to be passed to do_steps function
|
|
||||||
*
|
|
||||||
* @param[in] time_stamp_trigger settings of the sensor returned from sensor control function
|
|
||||||
* @param[in] inputs input structure containing the information on sensors to be passed to do_steps
|
|
||||||
* @param[in] num_bsec_inputs number of inputs to be passed to do_steps
|
|
||||||
* @param[in] bsec_process_data process data variable returned from sensor_control
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void bme680_bsec_read_data(int64_t time_stamp_trigger, bsec_input_t *inputs, uint8_t *num_bsec_inputs,
|
|
||||||
int32_t bsec_process_data)
|
|
||||||
{
|
|
||||||
static struct bme680_field_data data;
|
|
||||||
int8_t bme680_status = BME680_OK;
|
|
||||||
|
|
||||||
/* We only have to read data if the previous call the bsec_sensor_control() actually asked for it */
|
|
||||||
if (bsec_process_data)
|
|
||||||
{
|
|
||||||
bme680_status = bme680_get_sensor_data(&data, &bme680_g);
|
|
||||||
|
|
||||||
if (data.status & BME680_NEW_DATA_MSK)
|
|
||||||
{
|
|
||||||
/* Pressure to be processed by BSEC */
|
|
||||||
if (bsec_process_data & BSEC_PROCESS_PRESSURE)
|
|
||||||
{
|
|
||||||
/* Place presssure sample into input struct */
|
|
||||||
inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
|
|
||||||
inputs[*num_bsec_inputs].signal = data.pressure;
|
|
||||||
inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
|
|
||||||
(*num_bsec_inputs)++;
|
|
||||||
}
|
|
||||||
/* Temperature to be processed by BSEC */
|
|
||||||
if (bsec_process_data & BSEC_PROCESS_TEMPERATURE)
|
|
||||||
{
|
|
||||||
/* Place temperature sample into input struct */
|
|
||||||
inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
|
|
||||||
#ifdef BME680_FLOAT_POINT_COMPENSATION
|
|
||||||
inputs[*num_bsec_inputs].signal = data.temperature;
|
|
||||||
#else
|
|
||||||
inputs[*num_bsec_inputs].signal = data.temperature / 100.0f;
|
|
||||||
#endif
|
|
||||||
inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
|
|
||||||
(*num_bsec_inputs)++;
|
|
||||||
|
|
||||||
/* Also add optional heatsource input which will be subtracted from the temperature reading to
|
|
||||||
* compensate for device-specific self-heating (supported in BSEC IAQ solution)*/
|
|
||||||
inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
|
|
||||||
inputs[*num_bsec_inputs].signal = bme680_temperature_offset_g;
|
|
||||||
inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
|
|
||||||
(*num_bsec_inputs)++;
|
|
||||||
}
|
|
||||||
/* Humidity to be processed by BSEC */
|
|
||||||
if (bsec_process_data & BSEC_PROCESS_HUMIDITY)
|
|
||||||
{
|
|
||||||
/* Place humidity sample into input struct */
|
|
||||||
inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
|
|
||||||
#ifdef BME680_FLOAT_POINT_COMPENSATION
|
|
||||||
inputs[*num_bsec_inputs].signal = data.humidity;
|
|
||||||
#else
|
|
||||||
inputs[*num_bsec_inputs].signal = data.humidity / 1000.0f;
|
|
||||||
#endif
|
|
||||||
inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
|
|
||||||
(*num_bsec_inputs)++;
|
|
||||||
}
|
|
||||||
/* Gas to be processed by BSEC */
|
|
||||||
if (bsec_process_data & BSEC_PROCESS_GAS)
|
|
||||||
{
|
|
||||||
/* Check whether gas_valid flag is set */
|
|
||||||
if(data.status & BME680_GASM_VALID_MSK)
|
|
||||||
{
|
|
||||||
/* Place sample into input struct */
|
|
||||||
inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
|
|
||||||
inputs[*num_bsec_inputs].signal = data.gas_resistance;
|
|
||||||
inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
|
|
||||||
(*num_bsec_inputs)++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief This function is written to process the sensor data for the requested virtual sensors
|
|
||||||
*
|
|
||||||
* @param[in] bsec_inputs input structure containing the information on sensors to be passed to do_steps
|
|
||||||
* @param[in] num_bsec_inputs number of inputs to be passed to do_steps
|
|
||||||
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void bme680_bsec_process_data(bsec_input_t *bsec_inputs, uint8_t num_bsec_inputs, output_ready_fct output_ready)
|
|
||||||
{
|
|
||||||
/* Output buffer set to the maximum virtual sensor outputs supported */
|
|
||||||
bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
|
|
||||||
uint8_t num_bsec_outputs = 0;
|
|
||||||
uint8_t index = 0;
|
|
||||||
|
|
||||||
bsec_library_return_t bsec_status = BSEC_OK;
|
|
||||||
|
|
||||||
int64_t timestamp = 0;
|
|
||||||
float iaq = 0.0f;
|
|
||||||
uint8_t iaq_accuracy = 0;
|
|
||||||
float temp = 0.0f;
|
|
||||||
float raw_temp = 0.0f;
|
|
||||||
float raw_pressure = 0.0f;
|
|
||||||
float humidity = 0.0f;
|
|
||||||
float raw_humidity = 0.0f;
|
|
||||||
float raw_gas = 0.0f;
|
|
||||||
float static_iaq = 0.0f;
|
|
||||||
uint8_t static_iaq_accuracy = 0;
|
|
||||||
float co2_equivalent = 0.0f;
|
|
||||||
uint8_t co2_accuracy = 0;
|
|
||||||
float breath_voc_equivalent = 0.0f;
|
|
||||||
uint8_t breath_voc_accuracy = 0;
|
|
||||||
float comp_gas_value = 0.0f;
|
|
||||||
uint8_t comp_gas_accuracy = 0;
|
|
||||||
float gas_percentage = 0.0f;
|
|
||||||
uint8_t gas_percentage_acccuracy = 0;
|
|
||||||
|
|
||||||
/* Check if something should be processed by BSEC */
|
|
||||||
if (num_bsec_inputs > 0)
|
|
||||||
{
|
|
||||||
/* Set number of outputs to the size of the allocated buffer */
|
|
||||||
/* BSEC_NUMBER_OUTPUTS to be defined */
|
|
||||||
num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
|
|
||||||
|
|
||||||
/* Perform processing of the data by BSEC
|
|
||||||
Note:
|
|
||||||
* The number of outputs you get depends on what you asked for during bsec_update_subscription(). This is
|
|
||||||
handled under bme680_bsec_update_subscription() function in this example file.
|
|
||||||
* The number of actual outputs that are returned is written to num_bsec_outputs. */
|
|
||||||
bsec_status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
|
|
||||||
|
|
||||||
/* Iterate through the outputs and extract the relevant ones. */
|
|
||||||
for (index = 0; index < num_bsec_outputs; index++)
|
|
||||||
{
|
|
||||||
switch (bsec_outputs[index].sensor_id)
|
|
||||||
{
|
|
||||||
case BSEC_OUTPUT_IAQ:
|
|
||||||
iaq = bsec_outputs[index].signal;
|
|
||||||
iaq_accuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_STATIC_IAQ:
|
|
||||||
static_iaq = bsec_outputs[index].signal;
|
|
||||||
static_iaq_accuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
|
||||||
co2_equivalent = bsec_outputs[index].signal;
|
|
||||||
co2_accuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
|
||||||
breath_voc_equivalent = bsec_outputs[index].signal;
|
|
||||||
breath_voc_accuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
|
||||||
temp = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
|
||||||
raw_pressure = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
|
||||||
humidity = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_RAW_GAS:
|
|
||||||
raw_gas = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
|
||||||
raw_temp = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
|
||||||
raw_humidity = bsec_outputs[index].signal;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_COMPENSATED_GAS:
|
|
||||||
comp_gas_value = bsec_outputs[index].signal;
|
|
||||||
comp_gas_accuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
|
||||||
gas_percentage = bsec_outputs[index].signal;
|
|
||||||
gas_percentage_acccuracy = bsec_outputs[index].accuracy;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assume that all the returned timestamps are the same */
|
|
||||||
timestamp = bsec_outputs[index].time_stamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pass the extracted outputs to the user provided output_ready() function. */
|
|
||||||
output_ready(timestamp, iaq, iaq_accuracy, temp, humidity, raw_pressure, raw_temp,
|
|
||||||
raw_humidity, raw_gas, bsec_status, static_iaq, co2_equivalent, breath_voc_equivalent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
|
|
||||||
*
|
|
||||||
* @param[in] sleep pointer to the system specific sleep function
|
|
||||||
* @param[in] get_timestamp_us pointer to the system specific timestamp derivation function
|
|
||||||
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
|
|
||||||
* @param[in] state_save pointer to the system-specific state save function
|
|
||||||
* @param[in] save_intvl interval at which BSEC state should be saved (in samples)
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
|
|
||||||
state_save_fct state_save, uint32_t save_intvl)
|
|
||||||
{
|
|
||||||
/* Timestamp variables */
|
|
||||||
int64_t time_stamp = 0;
|
|
||||||
int64_t time_stamp_interval_ms = 0;
|
|
||||||
|
|
||||||
/* Allocate enough memory for up to BSEC_MAX_PHYSICAL_SENSOR physical inputs*/
|
|
||||||
bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
|
|
||||||
|
|
||||||
/* Number of inputs to BSEC */
|
|
||||||
uint8_t num_bsec_inputs = 0;
|
|
||||||
|
|
||||||
/* BSEC sensor settings struct */
|
|
||||||
bsec_bme_settings_t sensor_settings;
|
|
||||||
|
|
||||||
/* Save state variables */
|
|
||||||
uint8_t bsec_state[BSEC_MAX_STATE_BLOB_SIZE];
|
|
||||||
uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
|
|
||||||
uint32_t bsec_state_len = 0;
|
|
||||||
uint32_t n_samples = 0;
|
|
||||||
|
|
||||||
bsec_library_return_t bsec_status = BSEC_OK;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* get the timestamp in nanoseconds before calling bsec_sensor_control() */
|
|
||||||
time_stamp = get_timestamp_us() * 1000;
|
|
||||||
|
|
||||||
/* Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control */
|
|
||||||
bsec_sensor_control(time_stamp, &sensor_settings);
|
|
||||||
|
|
||||||
/* Trigger a measurement if necessary */
|
|
||||||
bme680_bsec_trigger_measurement(&sensor_settings, sleep);
|
|
||||||
|
|
||||||
/* Read data from last measurement */
|
|
||||||
num_bsec_inputs = 0;
|
|
||||||
bme680_bsec_read_data(time_stamp, bsec_inputs, &num_bsec_inputs, sensor_settings.process_data);
|
|
||||||
|
|
||||||
/* Time to invoke BSEC to perform the actual processing */
|
|
||||||
bme680_bsec_process_data(bsec_inputs, num_bsec_inputs, output_ready);
|
|
||||||
|
|
||||||
/* Increment sample counter */
|
|
||||||
n_samples++;
|
|
||||||
|
|
||||||
/* Retrieve and store state if the passed save_intvl */
|
|
||||||
if (n_samples >= save_intvl)
|
|
||||||
{
|
|
||||||
bsec_status = bsec_get_state(0, bsec_state, sizeof(bsec_state), work_buffer, sizeof(work_buffer), &bsec_state_len);
|
|
||||||
if (bsec_status == BSEC_OK)
|
|
||||||
{
|
|
||||||
state_save(bsec_state, bsec_state_len);
|
|
||||||
}
|
|
||||||
n_samples = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Compute how long we can sleep until we need to call bsec_sensor_control() next */
|
|
||||||
/* Time_stamp is converted from microseconds to nanoseconds first and then the difference to milliseconds */
|
|
||||||
time_stamp_interval_ms = (sensor_settings.next_call - get_timestamp_us() * 1000) / 1000000;
|
|
||||||
if (time_stamp_interval_ms > 0)
|
|
||||||
{
|
|
||||||
sleep((uint32_t)time_stamp_interval_ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,165 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_integration.h
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Contains BSEC integration API
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
#ifndef __BSEC_INTEGRATION_H__
|
|
||||||
#define __BSEC_INTEGRATION_H__
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/* Use the following bme680 driver: https://github.com/BoschSensortec/BME680_driver/releases/tag/bme680_v3.5.1 */
|
|
||||||
#include "bme680.h"
|
|
||||||
/* BSEC header files are available in the inc/ folder of the release package */
|
|
||||||
#include "bsec_interface.h"
|
|
||||||
#include "bsec_datatypes.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* type definitions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/* function pointer to the system specific sleep function */
|
|
||||||
typedef void (*sleep_fct)(uint32_t t_ms);
|
|
||||||
|
|
||||||
/* function pointer to the system specific timestamp derivation function */
|
|
||||||
typedef int64_t (*get_timestamp_us_fct)();
|
|
||||||
|
|
||||||
/* function pointer to the function processing obtained BSEC outputs */
|
|
||||||
typedef void (*output_ready_fct)(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
|
||||||
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
|
||||||
float static_iaq, float co2_equivalent, float breath_voc_equivalent);
|
|
||||||
|
|
||||||
/* function pointer to the function loading a previous BSEC state from NVM */
|
|
||||||
typedef uint32_t (*state_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
|
|
||||||
|
|
||||||
/* function pointer to the function saving BSEC state to NVM */
|
|
||||||
typedef void (*state_save_fct)(const uint8_t *state_buffer, uint32_t length);
|
|
||||||
|
|
||||||
/* function pointer to the function loading the BSEC configuration string from NVM */
|
|
||||||
typedef uint32_t (*config_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
|
|
||||||
|
|
||||||
/* structure definitions */
|
|
||||||
|
|
||||||
/* Structure with the return value from bsec_iot_init() */
|
|
||||||
typedef struct{
|
|
||||||
/*! Result of API execution status */
|
|
||||||
int8_t bme680_status;
|
|
||||||
/*! Result of BSEC library */
|
|
||||||
bsec_library_return_t bsec_status;
|
|
||||||
}return_values_init;
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* function declarations */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Initialize the BME680 sensor and the BSEC library
|
|
||||||
*
|
|
||||||
* @param[in] sample_rate mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
|
|
||||||
* @param[in] temperature_offset device-specific temperature offset (due to self-heating)
|
|
||||||
* @param[in] bus_write pointer to the bus writing function
|
|
||||||
* @param[in] bus_read pointer to the bus reading function
|
|
||||||
* @param[in] sleep pointer to the system-specific sleep function
|
|
||||||
* @param[in] state_load pointer to the system-specific state load function
|
|
||||||
*
|
|
||||||
* @return zero if successful, negative otherwise
|
|
||||||
*/
|
|
||||||
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write, bme680_com_fptr_t bus_read,
|
|
||||||
sleep_fct sleep, state_load_fct state_load, config_load_fct config_load);
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
|
|
||||||
*
|
|
||||||
* @param[in] sleep pointer to the system-specific sleep function
|
|
||||||
* @param[in] get_timestamp_us pointer to the system-specific timestamp derivation function
|
|
||||||
* @param[in] output_ready pointer to the function processing obtained BSEC outputs
|
|
||||||
* @param[in] state_save pointer to the system-specific state save function
|
|
||||||
* @param[in] save_intvl interval at which BSEC state should be saved (in samples)
|
|
||||||
*
|
|
||||||
* @return return_values_init struct with the result of the API and the BSEC library
|
|
||||||
*/
|
|
||||||
void bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
|
|
||||||
state_save_fct state_save, uint32_t save_intvl);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __BSEC_INTEGRATION_H__ */
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,258 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_iot_example.c
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Example for using of BSEC library in a fixed configuration with the BME680 sensor.
|
|
||||||
* This works by running an endless loop in the bsec_iot_loop() function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
#include "bsec_integration.h"
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* functions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Write operation in either I2C or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr I2C or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[in] reg_data_ptr pointer to the data to be written
|
|
||||||
* param[in] data_len number of bytes to be written
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to write to the bus where BME680 is connected
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Read operation in either I2C or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr I2C or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
|
|
||||||
* param[in] data_len number of bytes to be read
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to read from bus where BME680 is connected
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief System specific implementation of sleep function
|
|
||||||
*
|
|
||||||
* @param[in] t_ms time in milliseconds
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void sleep(uint32_t t_ms)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function sleep or delay for t_ms milliseconds
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Capture the system time in microseconds
|
|
||||||
*
|
|
||||||
* @return system_current_time current system timestamp in microseconds
|
|
||||||
*/
|
|
||||||
int64_t get_timestamp_us()
|
|
||||||
{
|
|
||||||
int64_t system_current_time = 0;
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to retrieve a timestamp (in microseconds)
|
|
||||||
// ...
|
|
||||||
return system_current_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Handling of the ready outputs
|
|
||||||
*
|
|
||||||
* @param[in] timestamp time in nanoseconds
|
|
||||||
* @param[in] iaq IAQ signal
|
|
||||||
* @param[in] iaq_accuracy accuracy of IAQ signal
|
|
||||||
* @param[in] temperature temperature signal
|
|
||||||
* @param[in] humidity humidity signal
|
|
||||||
* @param[in] pressure pressure signal
|
|
||||||
* @param[in] raw_temperature raw temperature signal
|
|
||||||
* @param[in] raw_humidity raw humidity signal
|
|
||||||
* @param[in] gas raw gas sensor signal
|
|
||||||
* @param[in] bsec_status value returned by the bsec_do_steps() call
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
|
||||||
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
|
||||||
float static_iaq, float co2_equivalent, float breath_voc_equivalent)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific code to further process or display the BSEC outputs
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load previous library state from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] state_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to state_buffer
|
|
||||||
*/
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a previous library state from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no state was available,
|
|
||||||
// otherwise return length of loaded state string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Save library state to non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in] state_buffer buffer holding the state to be stored
|
|
||||||
* @param[in] length length of the state string to be stored
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Save the string some form of non-volatile memory, if possible.
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load library config from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] config_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to config_buffer
|
|
||||||
*/
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
|
||||||
// otherwise return length of loaded config string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
|
|
||||||
* on timer ticks
|
|
||||||
*
|
|
||||||
* @return result of the processing
|
|
||||||
*/
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
return_values_init ret;
|
|
||||||
|
|
||||||
/* Call to the function which initializes the BSEC library
|
|
||||||
* Switch on low-power mode and provide no temperature offset */
|
|
||||||
ret = bsec_iot_init(BSEC_SAMPLE_RATE_LP, 0.0f, bus_write, bus_read, sleep, state_load, config_load);
|
|
||||||
if (ret.bme680_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BME680 */
|
|
||||||
return (int)ret.bme680_status;
|
|
||||||
}
|
|
||||||
else if (ret.bsec_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BSEC library */
|
|
||||||
return (int)ret.bsec_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call to endless loop function which reads and processes data based on sensor settings */
|
|
||||||
/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */
|
|
||||||
bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 10000);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,291 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_iot_example.ino
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Example for using of BSEC library in a fixed configuration with the BME680 sensor.
|
|
||||||
* This works by running an endless loop in the bsec_iot_loop() function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
#include "bsec_integration.h"
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* functions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Write operation in either Wire or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr Wire or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[in] reg_data_ptr pointer to the data to be written
|
|
||||||
* param[in] data_len number of bytes to be written
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
Wire.beginTransmission(dev_addr);
|
|
||||||
Wire.write(reg_addr); /* Set register address to start writing to */
|
|
||||||
|
|
||||||
/* Write the data */
|
|
||||||
for (int index = 0; index < data_len; index++) {
|
|
||||||
Wire.write(reg_data_ptr[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int8_t)Wire.endTransmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Read operation in either Wire or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr Wire or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
|
|
||||||
* param[in] data_len number of bytes to be read
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
int8_t comResult = 0;
|
|
||||||
Wire.beginTransmission(dev_addr);
|
|
||||||
Wire.write(reg_addr); /* Set register address to start reading from */
|
|
||||||
comResult = Wire.endTransmission();
|
|
||||||
|
|
||||||
delayMicroseconds(150); /* Precautionary response delay */
|
|
||||||
Wire.requestFrom(dev_addr, (uint8_t)data_len); /* Request data */
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
while (Wire.available()) /* The slave device may send less than requested (burst read) */
|
|
||||||
{
|
|
||||||
reg_data_ptr[index] = Wire.read();
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return comResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief System specific implementation of sleep function
|
|
||||||
*
|
|
||||||
* @param[in] t_ms time in milliseconds
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void sleep(uint32_t t_ms)
|
|
||||||
{
|
|
||||||
delay(t_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Capture the system time in microseconds
|
|
||||||
*
|
|
||||||
* @return system_current_time current system timestamp in microseconds
|
|
||||||
*/
|
|
||||||
int64_t get_timestamp_us()
|
|
||||||
{
|
|
||||||
return (int64_t) millis() * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Handling of the ready outputs
|
|
||||||
*
|
|
||||||
* @param[in] timestamp time in nanoseconds
|
|
||||||
* @param[in] iaq IAQ signal
|
|
||||||
* @param[in] iaq_accuracy accuracy of IAQ signal
|
|
||||||
* @param[in] temperature temperature signal
|
|
||||||
* @param[in] humidity humidity signal
|
|
||||||
* @param[in] pressure pressure signal
|
|
||||||
* @param[in] raw_temperature raw temperature signal
|
|
||||||
* @param[in] raw_humidity raw humidity signal
|
|
||||||
* @param[in] gas raw gas sensor signal
|
|
||||||
* @param[in] bsec_status value returned by the bsec_do_steps() call
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
|
||||||
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
|
||||||
float static_iaq, float co2_equivalent, float breath_voc_equivalent)
|
|
||||||
{
|
|
||||||
Serial.print("[");
|
|
||||||
Serial.print(timestamp/1e6);
|
|
||||||
Serial.print("] T: ");
|
|
||||||
Serial.print(temperature);
|
|
||||||
Serial.print("| rH: ");
|
|
||||||
Serial.print(humidity);
|
|
||||||
Serial.print("| IAQ: ");
|
|
||||||
Serial.print(iaq);
|
|
||||||
Serial.print(" (");
|
|
||||||
Serial.print(iaq_accuracy);
|
|
||||||
Serial.print("| Static IAQ: ");
|
|
||||||
Serial.print(static_iaq);
|
|
||||||
Serial.print("| CO2e: ");
|
|
||||||
Serial.print(co2_equivalent);
|
|
||||||
Serial.print("| bVOC: ");
|
|
||||||
Serial.println(breath_voc_equivalent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load previous library state from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] state_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to state_buffer
|
|
||||||
*/
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a previous library state from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no state was available,
|
|
||||||
// otherwise return length of loaded state string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Save library state to non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in] state_buffer buffer holding the state to be stored
|
|
||||||
* @param[in] length length of the state string to be stored
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Save the string some form of non-volatile memory, if possible.
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load library config from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] config_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to config_buffer
|
|
||||||
*/
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
|
||||||
// otherwise return length of loaded config string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
|
|
||||||
* on timer ticks
|
|
||||||
*
|
|
||||||
* @return result of the processing
|
|
||||||
*/
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
return_values_init ret;
|
|
||||||
|
|
||||||
/* Init I2C and serial communication */
|
|
||||||
Wire.begin();
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
/* Call to the function which initializes the BSEC library
|
|
||||||
* Switch on low-power mode and provide no temperature offset */
|
|
||||||
ret = bsec_iot_init(BSEC_SAMPLE_RATE_LP, 5.0f, bus_write, bus_read, sleep, state_load, config_load);
|
|
||||||
if (ret.bme680_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BME680 */
|
|
||||||
Serial.println("Error while initializing BME680");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ret.bsec_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BSEC library */
|
|
||||||
Serial.println("Error while initializing BSEC library");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call to endless loop function which reads and processes data based on sensor settings */
|
|
||||||
/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */
|
|
||||||
bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,290 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_iot_ulp_plus_example.c
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Example for using of BSEC library in a fixed configuration with the BME680 sensor.
|
|
||||||
* This works by running an endless loop in the bsec_iot_loop() function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* BSEC configuration files are available in the config/ folder of the release package. Please chose a configuration file with 3s maximum time between `bsec_sensor_control()` calls */
|
|
||||||
#include "bsec_integration.h"
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* functions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Write operation in either I2C or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr I2C or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[in] reg_data_ptr pointer to the data to be written
|
|
||||||
* param[in] data_len number of bytes to be written
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to write to the bus where BME680 is connected
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Read operation in either I2C or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr I2C or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
|
|
||||||
* param[in] data_len number of bytes to be read
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to read from bus where BME680 is connected
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief System specific implementation of sleep function
|
|
||||||
*
|
|
||||||
* @param[in] t_ms time in milliseconds
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void sleep(uint32_t t_ms)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function sleep or delay for t_ms milliseconds
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Capture the system time in microseconds
|
|
||||||
*
|
|
||||||
* @return system_current_time current system timestamp in microseconds
|
|
||||||
*/
|
|
||||||
int64_t get_timestamp_us()
|
|
||||||
{
|
|
||||||
int64_t system_current_time = 0;
|
|
||||||
// ...
|
|
||||||
// Please insert system specific function to retrieve a timestamp (in microseconds)
|
|
||||||
// ...
|
|
||||||
return system_current_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Handling of the ready outputs
|
|
||||||
*
|
|
||||||
* @param[in] timestamp time in nanoseconds
|
|
||||||
* @param[in] iaq IAQ signal
|
|
||||||
* @param[in] iaq_accuracy accuracy of IAQ signal
|
|
||||||
* @param[in] temperature temperature signal
|
|
||||||
* @param[in] humidity humidity signal
|
|
||||||
* @param[in] pressure pressure signal
|
|
||||||
* @param[in] raw_temperature raw temperature signal
|
|
||||||
* @param[in] raw_humidity raw humidity signal
|
|
||||||
* @param[in] gas raw gas sensor signal
|
|
||||||
* @param[in] bsec_status value returned by the bsec_do_steps() call
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
|
||||||
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
|
||||||
float static_iaq, float co2_equivalent, float breath_voc_equivalent)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Please insert system specific code to further process or display the BSEC outputs
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load previous library state from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] state_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to state_buffer
|
|
||||||
*/
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a previous library state from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no state was available,
|
|
||||||
// otherwise return length of loaded state string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Save library state to non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in] state_buffer buffer holding the state to be stored
|
|
||||||
* @param[in] length length of the state string to be stored
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Save the string some form of non-volatile memory, if possible.
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load library config from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] config_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to config_buffer
|
|
||||||
*/
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
|
||||||
// otherwise return length of loaded config string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Interrupt handler for press of a ULP plus button
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
bsec_sensor_configuration_t requested_virtual_sensors[1];
|
|
||||||
uint8_t n_requested_virtual_sensors = 1;
|
|
||||||
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
|
|
||||||
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
|
|
||||||
bsec_library_return_t status = BSEC_OK;
|
|
||||||
|
|
||||||
/* To trigger a ULP plus, we request the IAQ virtual sensor with a specific sample rate code */
|
|
||||||
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
|
|
||||||
requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND;
|
|
||||||
|
|
||||||
/* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
|
|
||||||
status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
|
|
||||||
&n_required_sensor_settings);
|
|
||||||
|
|
||||||
/* The status code would tell is if the request was accepted. It will be rejected if the sensor is not already in
|
|
||||||
* ULP mode, or if the time difference between requests is too short, for example. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
|
|
||||||
* on timer ticks
|
|
||||||
*
|
|
||||||
* @return result of the processing
|
|
||||||
*/
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
return_values_init ret;
|
|
||||||
// ...
|
|
||||||
// Attach a button (or other) interrupt here to the ulp_plus_button_press() handler function to
|
|
||||||
// enable this interrupt to trigger a ULP plus
|
|
||||||
// ...
|
|
||||||
|
|
||||||
/* Call to the function which initializes the BSEC library
|
|
||||||
* Switch on ultra_low-power mode and provide no temperature offset */
|
|
||||||
ret = bsec_iot_init(BSEC_SAMPLE_RATE_ULP, 0.0f, bus_write, bus_read, sleep, state_load, config_load);
|
|
||||||
if (ret.bme680_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BME680 or BSEC library */
|
|
||||||
return (int)ret.bme680_status;
|
|
||||||
}
|
|
||||||
else if (ret.bsec_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BSEC library */
|
|
||||||
return (int)ret.bsec_status;
|
|
||||||
}
|
|
||||||
/* Call to endless loop function which reads and processes data based on sensor settings */
|
|
||||||
/* State is saved every 10.000 samples, which means every 100 * 300 secs = 500 minutes */
|
|
||||||
bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 100);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,342 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Disclaimer
|
|
||||||
*
|
|
||||||
* Common:
|
|
||||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
|
||||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
|
||||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
|
||||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
|
||||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
|
||||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
|
||||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
|
||||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
|
||||||
*
|
|
||||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
|
||||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
|
||||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
|
||||||
* Sensortec for all costs in connection with such claims.
|
|
||||||
*
|
|
||||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
|
||||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
|
||||||
*
|
|
||||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
|
||||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
|
||||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
|
||||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
|
||||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
|
||||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
|
||||||
* samples.
|
|
||||||
*
|
|
||||||
* Special:
|
|
||||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
|
||||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
|
||||||
* application work. The Software and Information is subject to the following terms and conditions:
|
|
||||||
*
|
|
||||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
|
||||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
|
||||||
* proper experience or training.
|
|
||||||
*
|
|
||||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
|
||||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose.
|
|
||||||
*
|
|
||||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
|
||||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
|
||||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
|
||||||
* otherwise stipulated in mandatory applicable law.
|
|
||||||
*
|
|
||||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
|
||||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
|
||||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
|
||||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
|
||||||
* subject to change without notice.
|
|
||||||
*
|
|
||||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
|
||||||
* Bosch Sensortec.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @file bsec_iot_ulp_plus_example.ino
|
|
||||||
*
|
|
||||||
* @brief
|
|
||||||
* Example for using of BSEC library in a fixed configuration with the BME680 sensor.
|
|
||||||
* This works by running an endless loop in the bsec_iot_loop() function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @addtogroup bsec_examples BSEC Examples
|
|
||||||
* @brief BSEC usage examples
|
|
||||||
* @{*/
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* header files */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
#include "bsec_integration.h"
|
|
||||||
#include "bsec_serialized_configurations_iaq.h"
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
/* functions */
|
|
||||||
/**********************************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Write operation in either Wire or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr Wire or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[in] reg_data_ptr pointer to the data to be written
|
|
||||||
* param[in] data_len number of bytes to be written
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
Wire.beginTransmission(dev_addr);
|
|
||||||
Wire.write(reg_addr); /* Set register address to start writing to */
|
|
||||||
|
|
||||||
/* Write the data */
|
|
||||||
for (int index = 0; index < data_len; index++) {
|
|
||||||
Wire.write(reg_data_ptr[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int8_t)Wire.endTransmission();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Read operation in either Wire or SPI
|
|
||||||
*
|
|
||||||
* param[in] dev_addr Wire or SPI device address
|
|
||||||
* param[in] reg_addr register address
|
|
||||||
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
|
|
||||||
* param[in] data_len number of bytes to be read
|
|
||||||
*
|
|
||||||
* @return result of the bus communication function
|
|
||||||
*/
|
|
||||||
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
|
||||||
{
|
|
||||||
int8_t comResult = 0;
|
|
||||||
Wire.beginTransmission(dev_addr);
|
|
||||||
Wire.write(reg_addr); /* Set register address to start reading from */
|
|
||||||
comResult = Wire.endTransmission();
|
|
||||||
|
|
||||||
delayMicroseconds(150); /* Precautionary response delay */
|
|
||||||
Wire.requestFrom(dev_addr, (uint8_t)data_len); /* Request data */
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
while (Wire.available()) /* The slave device may send less than requested (burst read) */
|
|
||||||
{
|
|
||||||
reg_data_ptr[index] = Wire.read();
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return comResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief System specific implementation of sleep function
|
|
||||||
*
|
|
||||||
* @param[in] t_ms time in milliseconds
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void sleep(uint32_t t_ms)
|
|
||||||
{
|
|
||||||
delay(t_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Capture the system time in microseconds
|
|
||||||
*
|
|
||||||
* @return system_current_time current system timestamp in microseconds
|
|
||||||
*/
|
|
||||||
int64_t get_timestamp_us()
|
|
||||||
{
|
|
||||||
return (int64_t) millis() * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Handling of the ready outputs
|
|
||||||
*
|
|
||||||
* @param[in] timestamp time in nanoseconds
|
|
||||||
* @param[in] iaq IAQ signal
|
|
||||||
* @param[in] iaq_accuracy accuracy of IAQ signal
|
|
||||||
* @param[in] temperature temperature signal
|
|
||||||
* @param[in] humidity humidity signal
|
|
||||||
* @param[in] pressure pressure signal
|
|
||||||
* @param[in] raw_temperature raw temperature signal
|
|
||||||
* @param[in] raw_humidity raw humidity signal
|
|
||||||
* @param[in] gas raw gas sensor signal
|
|
||||||
* @param[in] bsec_status value returned by the bsec_do_steps() call
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
|
||||||
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
|
||||||
float static_iaq, float co2_equivalent, float breath_voc_equivalent)
|
|
||||||
{
|
|
||||||
Serial.print("[");
|
|
||||||
Serial.print(timestamp/1e6);
|
|
||||||
Serial.print("] T: ");
|
|
||||||
Serial.print(temperature);
|
|
||||||
Serial.print("| rH: ");
|
|
||||||
Serial.print(humidity);
|
|
||||||
Serial.print("| IAQ: ");
|
|
||||||
Serial.print(iaq);
|
|
||||||
Serial.print(" (");
|
|
||||||
Serial.print(iaq_accuracy);
|
|
||||||
Serial.println(")");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load previous library state from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] state_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to state_buffer
|
|
||||||
*/
|
|
||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a previous library state from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no state was available,
|
|
||||||
// otherwise return length of loaded state string.
|
|
||||||
// ...
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Save library state to non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in] state_buffer buffer holding the state to be stored
|
|
||||||
* @param[in] length length of the state string to be stored
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void state_save(const uint8_t *state_buffer, uint32_t length)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Save the string some form of non-volatile memory, if possible.
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Load library config from non-volatile memory
|
|
||||||
*
|
|
||||||
* @param[in,out] config_buffer buffer to hold the loaded state string
|
|
||||||
* @param[in] n_buffer size of the allocated state buffer
|
|
||||||
*
|
|
||||||
* @return number of bytes copied to config_buffer
|
|
||||||
*/
|
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
|
||||||
// otherwise return length of loaded config string.
|
|
||||||
// ...
|
|
||||||
|
|
||||||
memcpy(config_buffer, bsec_config_iaq, sizeof(bsec_config_iaq));
|
|
||||||
return sizeof(bsec_config_iaq);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Interrupt handler for press of a ULP plus button
|
|
||||||
*
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
bsec_sensor_configuration_t requested_virtual_sensors[1];
|
|
||||||
uint8_t n_requested_virtual_sensors = 1;
|
|
||||||
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
|
|
||||||
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
|
|
||||||
bsec_library_return_t status = BSEC_OK;
|
|
||||||
|
|
||||||
/* To trigger a ULP plus, we request the IAQ virtual sensor with a specific sample rate code */
|
|
||||||
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ_ESTIMATE;
|
|
||||||
requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND;
|
|
||||||
|
|
||||||
/* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
|
|
||||||
status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
|
|
||||||
&n_required_sensor_settings);
|
|
||||||
|
|
||||||
/* The status code would tell is if the request was accepted. It will be rejected if the sensor is not already in
|
|
||||||
* ULP mode, or if the time difference between requests is too short, for example. */
|
|
||||||
if (status == BSEC_OK)
|
|
||||||
{
|
|
||||||
Serial.println("ULP plus triggered sucessfully.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.print("ULP plus request rejected. ");
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case BSEC_W_SC_MODEXCEEDULPTIMELIMIT:
|
|
||||||
Serial.println("Request came within 20 s of a previous measurement.");
|
|
||||||
break;
|
|
||||||
case BSEC_W_SC_MODINSUFFICIENTWAITTIME:
|
|
||||||
Serial.println("Request came within 20 s of a ULP plus.");
|
|
||||||
break;
|
|
||||||
case BSEC_W_SU_MODINNOULP:
|
|
||||||
Serial.println("Sensor not in ULP mode.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
|
|
||||||
* on timer ticks
|
|
||||||
*
|
|
||||||
* @return result of the processing
|
|
||||||
*/
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
return_values_init ret;
|
|
||||||
|
|
||||||
/* Init I2C and serial communication */
|
|
||||||
Wire.begin();
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
/* Setup button interrupt to trigger ULP plus */
|
|
||||||
pinMode(2, INPUT_PULLUP);
|
|
||||||
attachInterrupt(digitalPinToInterrupt(2), ulp_plus_button_press, FALLING);
|
|
||||||
|
|
||||||
/* Call to the function which initializes the BSEC library
|
|
||||||
* Switch on ultra_low-power mode and provide no temperature offset */
|
|
||||||
ret = bsec_iot_init(BSEC_SAMPLE_RATE_ULP, 5.0f, bus_write, bus_read, sleep, state_load, config_load);
|
|
||||||
if (ret.bme680_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BME680 */
|
|
||||||
Serial.println("Error while initializing BME680");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ret.bsec_status)
|
|
||||||
{
|
|
||||||
/* Could not intialize BSEC library */
|
|
||||||
Serial.println("Error while initializing BSEC library");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call to endless loop function which reads and processes data based on sensor settings */
|
|
||||||
/* State is saved every 10.000 samples, which means every 100 * 300 secs = 500 minutes */
|
|
||||||
bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! @}*/
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
text data bss dec hex filename
|
|
||||||
23795 0 1120 24915 6153 (TOTALS)
|
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||||
[platformio]
|
[platformio]
|
||||||
;env_default = generic
|
env_default = generic
|
||||||
;env_default = ebox
|
;env_default = ebox
|
||||||
;env_default = eboxtube
|
;env_default = eboxtube
|
||||||
;env_default = heltec
|
;env_default = heltec
|
||||||
@ -15,7 +15,7 @@
|
|||||||
;env_default = ttgov2
|
;env_default = ttgov2
|
||||||
;env_default = ttgov21old
|
;env_default = ttgov21old
|
||||||
;env_default = ttgov21new
|
;env_default = ttgov21new
|
||||||
env_default = ttgobeam
|
;env_default = ttgobeam
|
||||||
;env_default = lopy
|
;env_default = lopy
|
||||||
;env_default = lopy4
|
;env_default = lopy4
|
||||||
;env_default = fipy
|
;env_default = fipy
|
||||||
@ -29,7 +29,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
|
|||||||
|
|
||||||
[common]
|
[common]
|
||||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||||
release_version = 1.6.85
|
release_version = 1.6.9
|
||||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||||
debug_level = 0
|
debug_level = 0
|
||||||
@ -38,12 +38,11 @@ upload_protocol = esptool
|
|||||||
;upload_protocol = custom
|
;upload_protocol = custom
|
||||||
extra_scripts = pre:build.py
|
extra_scripts = pre:build.py
|
||||||
keyfile = ota.conf
|
keyfile = ota.conf
|
||||||
;platform_espressif32 = espressif32@1.5.0
|
|
||||||
platform_espressif32 = https://github.com/platformio/platform-espressif32.git#a7b1fe6
|
platform_espressif32 = https://github.com/platformio/platform-espressif32.git#a7b1fe6
|
||||||
board_build.partitions = min_spiffs.csv
|
board_build.partitions = min_spiffs.csv
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
lib_deps_lora =
|
lib_deps_lora =
|
||||||
; MCCI LoRaWAN LMIC library@^2.2.2
|
; MCCI LoRaWAN LMIC library@2.3.0
|
||||||
lib_deps_display =
|
lib_deps_display =
|
||||||
U8g2@>=2.25.0
|
U8g2@>=2.25.0
|
||||||
lib_deps_rgbled =
|
lib_deps_rgbled =
|
||||||
|
@ -43,7 +43,7 @@ function Decoder(bytes, port) {
|
|||||||
|
|
||||||
if (port === 7) {
|
if (port === 7) {
|
||||||
// BME680 sensor data
|
// BME680 sensor data
|
||||||
return decode(bytes, [temperature, uint16, humidity, uint16], ['temperature', 'pressure', 'humidity', 'air']);
|
return decode(bytes, [float, uint16, ufloat, ufloat], ['temperature', 'pressure', 'humidity', 'air']);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -116,9 +116,9 @@ var hdop = function (bytes) {
|
|||||||
};
|
};
|
||||||
hdop.BYTES = 2;
|
hdop.BYTES = 2;
|
||||||
|
|
||||||
var temperature = function (bytes) {
|
var float = function (bytes) {
|
||||||
if (bytes.length !== temperature.BYTES) {
|
if (bytes.length !== float.BYTES) {
|
||||||
throw new Error('Temperature must have exactly 2 bytes');
|
throw new Error('Float must have exactly 2 bytes');
|
||||||
}
|
}
|
||||||
var isNegative = bytes[0] & 0x80;
|
var isNegative = bytes[0] & 0x80;
|
||||||
var b = ('00000000' + Number(bytes[0]).toString(2)).slice(-8)
|
var b = ('00000000' + Number(bytes[0]).toString(2)).slice(-8)
|
||||||
@ -139,17 +139,27 @@ var temperature = function (bytes) {
|
|||||||
}
|
}
|
||||||
return +(t / 100).toFixed(1);
|
return +(t / 100).toFixed(1);
|
||||||
};
|
};
|
||||||
temperature.BYTES = 2;
|
float.BYTES = 2;
|
||||||
|
|
||||||
var humidity = function (bytes) {
|
var ufloat = function (bytes) {
|
||||||
if (bytes.length !== humidity.BYTES) {
|
if (bytes.length !== ufloat.BYTES) {
|
||||||
throw new Error('Humidity must have exactly 2 bytes');
|
throw new Error('Ufloat must have exactly 2 bytes');
|
||||||
}
|
}
|
||||||
|
|
||||||
var h = bytesToInt(bytes);
|
var h = bytesToInt(bytes);
|
||||||
return +(h / 100).toFixed(1);
|
return +(h / 100).toFixed(1);
|
||||||
};
|
};
|
||||||
humidity.BYTES = 2;
|
ufloat.BYTES = 2;
|
||||||
|
|
||||||
|
var pressure = function (bytes) {
|
||||||
|
if (bytes.length !== pressure.BYTES) {
|
||||||
|
throw new Error('Pressure must have exactly 2 bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = bytesToInt(bytes);
|
||||||
|
return +(h / 10).toFixed(1);
|
||||||
|
};
|
||||||
|
pressure.BYTES = 2;
|
||||||
|
|
||||||
var bitmap = function (byte) {
|
var bitmap = function (byte) {
|
||||||
if (byte.length !== bitmap.BYTES) {
|
if (byte.length !== bitmap.BYTES) {
|
||||||
@ -193,8 +203,9 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
|||||||
uint16: uint16,
|
uint16: uint16,
|
||||||
uint32: uint32,
|
uint32: uint32,
|
||||||
uptime: uptime,
|
uptime: uptime,
|
||||||
temperature: temperature,
|
float: float,
|
||||||
humidity: humidity,
|
ufloat: ufloat,
|
||||||
|
pressure: pressure,
|
||||||
latLng: latLng,
|
latLng: latLng,
|
||||||
hdop: hdop,
|
hdop: hdop,
|
||||||
bitmap: bitmap,
|
bitmap: bitmap,
|
||||||
|
@ -8,6 +8,43 @@ static const char TAG[] = "main";
|
|||||||
bmeStatus_t bme_status;
|
bmeStatus_t bme_status;
|
||||||
TaskHandle_t BmeTask;
|
TaskHandle_t BmeTask;
|
||||||
|
|
||||||
|
// --- Bosch BSEC library configuration ---
|
||||||
|
// 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
|
||||||
|
// calibration. Change this const if not applicable for your application (see
|
||||||
|
// BME680 datasheet)
|
||||||
|
const uint8_t bsec_config_iaq[454] = {
|
||||||
|
1, 7, 4, 1, 61, 0, 0, 0, 0, 0, 0, 0, 174, 1, 0,
|
||||||
|
0, 48, 0, 1, 0, 137, 65, 0, 63, 205, 204, 204, 62, 0, 0,
|
||||||
|
64, 63, 205, 204, 204, 62, 0, 0, 225, 68, 0, 192, 168, 71, 64,
|
||||||
|
49, 119, 76, 0, 0, 0, 0, 0, 80, 5, 95, 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,
|
||||||
|
239, 79, 0, 0};
|
||||||
|
|
||||||
// initialize BME680 sensor
|
// initialize BME680 sensor
|
||||||
int bme_init(void) {
|
int bme_init(void) {
|
||||||
|
|
||||||
@ -22,9 +59,11 @@ int bme_init(void) {
|
|||||||
user_delay_ms, state_load, config_load);
|
user_delay_ms, state_load, config_load);
|
||||||
|
|
||||||
if ((int)ret.bme680_status) {
|
if ((int)ret.bme680_status) {
|
||||||
ESP_LOGE(TAG, "Could not initialize BME680, error %d", (int)ret.bme680_status);
|
ESP_LOGE(TAG, "Could not initialize BME680, error %d",
|
||||||
|
(int)ret.bme680_status);
|
||||||
} else if ((int)ret.bsec_status) {
|
} else if ((int)ret.bsec_status) {
|
||||||
ESP_LOGE(TAG, "Could not initialize BSEC library, error %d", (int)ret.bsec_status);
|
ESP_LOGE(TAG, "Could not initialize BSEC library, error %d",
|
||||||
|
(int)ret.bsec_status);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG, "BME680 sensor found and initialized");
|
ESP_LOGI(TAG, "BME680 sensor found and initialized");
|
||||||
return 1;
|
return 1;
|
||||||
@ -131,13 +170,13 @@ void state_save(const uint8_t *state_buffer, uint32_t length) {
|
|||||||
* @return number of bytes copied to config_buffer
|
* @return number of bytes copied to config_buffer
|
||||||
*/
|
*/
|
||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer) {
|
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer) {
|
||||||
// ...
|
|
||||||
// Load a library config from non-volatile memory, if available.
|
// Load a library config from non-volatile memory, if available.
|
||||||
//
|
|
||||||
// Return zero if loading was unsuccessful or no config was available,
|
// Return zero if loading was unsuccessful or no config was available,
|
||||||
// otherwise return length of loaded config string.
|
// otherwise return length of loaded config string.
|
||||||
// ...
|
|
||||||
return 0;
|
memcpy(config_buffer, bsec_config_iaq, sizeof(bsec_config_iaq));
|
||||||
|
return sizeof(bsec_config_iaq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -164,7 +164,7 @@ void onEvent(ev_t ev) {
|
|||||||
switch (ev) {
|
switch (ev) {
|
||||||
|
|
||||||
case EV_SCAN_TIMEOUT:
|
case EV_SCAN_TIMEOUT:
|
||||||
strcpy_P(buff, PSTR("SCAN TIMEOUT"));
|
strcpy_P(buff, PSTR("SCAN_TIMEOUT"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_BEACON_FOUND:
|
case EV_BEACON_FOUND:
|
||||||
@ -210,15 +210,21 @@ void onEvent(ev_t ev) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_TXCOMPLETE:
|
case EV_TXCOMPLETE:
|
||||||
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
|
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED_ACK")
|
||||||
: PSTR("TX COMPLETE"));
|
: PSTR("TX_COMPLETE"));
|
||||||
sprintf(display_line6, " "); // clear previous lmic status
|
sprintf(display_line6, " "); // clear previous lmic status
|
||||||
|
|
||||||
|
// if (LMIC.dataLen) {
|
||||||
|
// ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
|
||||||
|
// LMIC.dataLen, (signed char)LMIC.rssi, (signed
|
||||||
|
// char)LMIC.snr);
|
||||||
|
// sprintf(display_line6, "RSSI %d SNR %d", (signed char)LMIC.rssi,
|
||||||
|
// (signed char)LMIC.snr);
|
||||||
|
|
||||||
if (LMIC.dataLen) {
|
if (LMIC.dataLen) {
|
||||||
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
|
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI -%d SNR %d",
|
||||||
LMIC.dataLen, (signed char)LMIC.rssi, (signed char)LMIC.snr);
|
LMIC.dataLen, LMIC.rssi, LMIC.snr / 4);
|
||||||
sprintf(display_line6, "RSSI %d SNR %d", (signed char)LMIC.rssi,
|
sprintf(display_line6, "RSSI -%d SNR %d", LMIC.rssi, LMIC.snr / 4);
|
||||||
(signed char)LMIC.snr);
|
|
||||||
|
|
||||||
// check if command is received on command port, then call interpreter
|
// check if command is received on command port, then call interpreter
|
||||||
if ((LMIC.txrxFlags & TXRX_PORT) &&
|
if ((LMIC.txrxFlags & TXRX_PORT) &&
|
||||||
@ -237,20 +243,20 @@ void onEvent(ev_t ev) {
|
|||||||
|
|
||||||
case EV_RXCOMPLETE:
|
case EV_RXCOMPLETE:
|
||||||
// data received in ping slot
|
// data received in ping slot
|
||||||
strcpy_P(buff, PSTR("RX COMPLETE"));
|
strcpy_P(buff, PSTR("RX_COMPLETE"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_LINK_DEAD:
|
case EV_LINK_DEAD:
|
||||||
strcpy_P(buff, PSTR("LINK DEAD"));
|
strcpy_P(buff, PSTR("LINK_DEAD"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_LINK_ALIVE:
|
case EV_LINK_ALIVE:
|
||||||
strcpy_P(buff, PSTR("LINK ALIVE"));
|
strcpy_P(buff, PSTR("LINK_ALIVE"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_TXSTART:
|
case EV_TXSTART:
|
||||||
if (!(LMIC.opmode & OP_JOINING))
|
if (!(LMIC.opmode & OP_JOINING))
|
||||||
strcpy_P(buff, PSTR("TX START"));
|
strcpy_P(buff, PSTR("TX_START"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EV_SCAN_FOUND:
|
case EV_SCAN_FOUND:
|
||||||
@ -262,7 +268,7 @@ void onEvent(ev_t ev) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf_P(buff, PSTR("UNKNOWN EVENT %d"), ev);
|
sprintf_P(buff, PSTR("UNKNOWN_EVENT_%d"), ev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ void start_ota_update() {
|
|||||||
ESP_LOGI(TAG, "Starting Wifi OTA update");
|
ESP_LOGI(TAG, "Starting Wifi OTA update");
|
||||||
display(1, "**", WIFI_SSID);
|
display(1, "**", WIFI_SSID);
|
||||||
|
|
||||||
WiFi.mode(WIFI_AP_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
|
|
||||||
int i = WIFI_MAX_TRY, j = OTA_MAX_TRY;
|
int i = WIFI_MAX_TRY, j = OTA_MAX_TRY;
|
||||||
|
@ -104,15 +104,16 @@ void PayloadConvert::addBME(bmeStatus_t value) {
|
|||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
int16_t temperature = (int16_t)(value.temperature); // float -> int
|
int16_t temperature = (int16_t)(value.temperature); // float -> int
|
||||||
uint16_t humidity = (uint16_t)(value.humidity); // float -> int
|
uint16_t humidity = (uint16_t)(value.humidity); // float -> int
|
||||||
|
uint16_t pressure = (uint16_t)(value.pressure); // float -> int
|
||||||
uint16_t iaq = (uint16_t)(value.iaq); // float -> int
|
uint16_t iaq = (uint16_t)(value.iaq); // float -> int
|
||||||
buffer[cursor++] = highByte(temperature);
|
buffer[cursor++] = highByte(temperature);
|
||||||
buffer[cursor++] = lowByte(temperature);
|
buffer[cursor++] = lowByte(temperature);
|
||||||
buffer[cursor++] = highByte(value.pressure);
|
buffer[cursor++] = highByte(pressure);
|
||||||
buffer[cursor++] = lowByte(value.pressure);
|
buffer[cursor++] = lowByte(pressure);
|
||||||
buffer[cursor++] = highByte(humidity);
|
buffer[cursor++] = highByte(humidity);
|
||||||
buffer[cursor++] = lowByte(humidity);
|
buffer[cursor++] = lowByte(humidity);
|
||||||
buffer[cursor++] = highByte(value.iaq);
|
buffer[cursor++] = highByte(iaq);
|
||||||
buffer[cursor++] = lowByte(value.iaq);
|
buffer[cursor++] = lowByte(iaq);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,10 +193,10 @@ void PayloadConvert::addSensor(uint8_t buf[]) {
|
|||||||
|
|
||||||
void PayloadConvert::addBME(bmeStatus_t value) {
|
void PayloadConvert::addBME(bmeStatus_t value) {
|
||||||
#ifdef HAS_BME
|
#ifdef HAS_BME
|
||||||
writeTemperature(value.temperature);
|
writeFloat(value.temperature);
|
||||||
writeUint16(value.pressure);
|
writePressure(value.pressure);
|
||||||
writeHumidity(value.humidity);
|
writeUFloat(value.humidity);
|
||||||
writeUint16(value.iaq);
|
writeUFloat(value.iaq);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,8 +233,13 @@ void PayloadConvert::writeUint16(uint16_t i) { intToBytes(cursor, i, 2); }
|
|||||||
|
|
||||||
void PayloadConvert::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); }
|
void PayloadConvert::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); }
|
||||||
|
|
||||||
void PayloadConvert::writeHumidity(float humidity) {
|
void PayloadConvert::writeUFloat(float value) {
|
||||||
int16_t h = (int16_t)(humidity * 100);
|
int16_t h = (int16_t)(value * 100);
|
||||||
|
intToBytes(cursor, h, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PayloadConvert::writePressure(float value) {
|
||||||
|
int16_t h = (int16_t)(value);
|
||||||
intToBytes(cursor, h, 2);
|
intToBytes(cursor, h, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,9 +247,9 @@ void PayloadConvert::writeHumidity(float humidity) {
|
|||||||
* Uses a 16bit two's complement with two decimals, so the range is
|
* Uses a 16bit two's complement with two decimals, so the range is
|
||||||
* -327.68 to +327.67 degrees
|
* -327.68 to +327.67 degrees
|
||||||
*/
|
*/
|
||||||
void PayloadConvert::writeTemperature(float temperature) {
|
void PayloadConvert::writeFloat(float value) {
|
||||||
int16_t t = (int16_t)(temperature * 100);
|
int16_t t = (int16_t)(value * 100);
|
||||||
if (temperature < 0) {
|
if (value < 0) {
|
||||||
t = ~-t;
|
t = ~-t;
|
||||||
t = t + 1;
|
t = t + 1;
|
||||||
}
|
}
|
||||||
@ -371,11 +377,10 @@ void PayloadConvert::addBME(bmeStatus_t value) {
|
|||||||
// 0.1°C per bit => -3276,7 .. +3276,7 °C
|
// 0.1°C per bit => -3276,7 .. +3276,7 °C
|
||||||
int16_t temperature = (int16_t)(value.temperature * 10.0);
|
int16_t temperature = (int16_t)(value.temperature * 10.0);
|
||||||
// 0.1 hPa per bit => 0 .. 6553,6 hPa
|
// 0.1 hPa per bit => 0 .. 6553,6 hPa
|
||||||
uint16_t pressure = value.pressure * 10;
|
uint16_t pressure = (uint16_t)(value.pressure * 10);
|
||||||
// 0.5% per bit => 0 .. 128 %C
|
// 0.5% per bit => 0 .. 128 %C
|
||||||
uint8_t humidity = (uint8_t)(value.humidity * 2.0);
|
uint8_t humidity = (uint8_t)(value.humidity * 2.0);
|
||||||
// 0.01 IAQ per bit => 0 .. 655,36 IAQ
|
int16_t iaq = (int16_t)(value.iaq);
|
||||||
uint16_t iaq = (uint16_t) value.iaq * 100;
|
|
||||||
|
|
||||||
#if (PAYLOAD_ENCODER == 3)
|
#if (PAYLOAD_ENCODER == 3)
|
||||||
buffer[cursor++] = LPP_TEMPERATURE_CHANNEL;
|
buffer[cursor++] = LPP_TEMPERATURE_CHANNEL;
|
||||||
@ -395,9 +400,9 @@ void PayloadConvert::addBME(bmeStatus_t value) {
|
|||||||
buffer[cursor++] = LPP_HUMIDITY; // 1 byte 0.5 % Unsigned
|
buffer[cursor++] = LPP_HUMIDITY; // 1 byte 0.5 % Unsigned
|
||||||
buffer[cursor++] = humidity;
|
buffer[cursor++] = humidity;
|
||||||
#if (PAYLOAD_ENCODER == 3)
|
#if (PAYLOAD_ENCODER == 3)
|
||||||
buffer[cursor++] = LPP_GAS_CHANNEL;
|
buffer[cursor++] = LPP_AIR_CHANNEL;
|
||||||
#endif
|
#endif
|
||||||
buffer[cursor++] = LPP_ANALOG_INPUT; // 2 bytes 0.01 Signed
|
buffer[cursor++] = LPP_LUMINOSITY; // 2 bytes, 1.0 unsigned
|
||||||
buffer[cursor++] = highByte(iaq);
|
buffer[cursor++] = highByte(iaq);
|
||||||
buffer[cursor++] = lowByte(iaq);
|
buffer[cursor++] = lowByte(iaq);
|
||||||
#endif // HAS_BME
|
#endif // HAS_BME
|
||||||
|
@ -7,9 +7,20 @@ void SendPayload(uint8_t port) {
|
|||||||
MessageBuffer_t SendBuffer; // contains MessageSize, MessagePort, Message[]
|
MessageBuffer_t SendBuffer; // contains MessageSize, MessagePort, Message[]
|
||||||
|
|
||||||
SendBuffer.MessageSize = payload.getSize();
|
SendBuffer.MessageSize = payload.getSize();
|
||||||
SendBuffer.MessagePort = PAYLOAD_ENCODER <= 2
|
switch (PAYLOAD_ENCODER) {
|
||||||
? port
|
case 1:
|
||||||
: (PAYLOAD_ENCODER == 4 ? LPP2PORT : LPP1PORT);
|
case 2:
|
||||||
|
SendBuffer.MessagePort = port;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
SendBuffer.MessagePort = LPP1PORT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
SendBuffer.MessagePort = LPP2PORT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SendBuffer.MessagePort = port;
|
||||||
|
}
|
||||||
memcpy(SendBuffer.Message, payload.getBuffer(), payload.getSize());
|
memcpy(SendBuffer.Message, payload.getBuffer(), payload.getSize());
|
||||||
|
|
||||||
// enqueue message in device's send queues
|
// enqueue message in device's send queues
|
||||||
|
@ -4,25 +4,33 @@
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
#define SENSORBUFFER 10 // max. size of user sensor data buffer in bytes [default=20]
|
#define SENSORBUFFER \
|
||||||
|
10 // max. size of user sensor data buffer in bytes [default=20]
|
||||||
|
|
||||||
void sensor_init(void) {
|
void sensor_init(void) {
|
||||||
|
|
||||||
// this function is called dureing device startup
|
// this function is called during device startup
|
||||||
// put your sensor initialization routines here
|
// put your user sensor initialization routines here
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sensor_mask(uint8_t sensor_no) {
|
uint8_t sensor_mask(uint8_t sensor_no) {
|
||||||
switch (sensor_no) {
|
switch (sensor_no) {
|
||||||
|
case 0:
|
||||||
|
return (uint8_t)COUNT_DATA;
|
||||||
case 1:
|
case 1:
|
||||||
return (uint8_t)SENSOR1_DATA;
|
return (uint8_t)SENSOR1_DATA;
|
||||||
case 2:
|
case 2:
|
||||||
return (uint8_t)SENSOR2_DATA;
|
return (uint8_t)SENSOR2_DATA;
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
return (uint8_t)SENSOR3_DATA;
|
return (uint8_t)SENSOR3_DATA;
|
||||||
case 4:
|
case 4:
|
||||||
return (uint8_t)SENSOR4_DATA;
|
return (uint8_t)SENSOR4_DATA;
|
||||||
|
case 5:
|
||||||
|
return (uint8_t)GPS_DATA;
|
||||||
|
case 6:
|
||||||
|
return (uint8_t)MEMS_DATA;
|
||||||
|
case 7:
|
||||||
|
return (uint8_t)ALARM_DATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user