Merge pull request #210 from cyberman54/development

v1.6.9
This commit is contained in:
Verkehrsrot 2018-11-25 23:40:05 +01:00 committed by GitHub
commit e37c8ba732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 146 additions and 1971 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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};

View File

@ -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);
}
}
}
/*! @}*/

View File

@ -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__ */
/*! @}*/

View File

@ -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;
}
/*! @}*/

View File

@ -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()
{
}
/*! @}*/

View File

@ -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;
}
/*! @}*/

View File

@ -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()
{
}
/*! @}*/

View File

@ -1,2 +0,0 @@
text data bss dec hex filename
23795 0 1120 24915 6153 (TOTALS)

View File

@ -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 =

View File

@ -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,

View File

@ -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);
} }
/*! /*!

View File

@ -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;
} }

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
} }
} }