Merge pull request #233 from cyberman54/development-bme680-2
BME680 integration refactored
This commit is contained in:
		
						commit
						5bdc354a07
					
				@ -3,30 +3,52 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "globals.h"
 | 
					#include "globals.h"
 | 
				
			||||||
#include <Wire.h>
 | 
					#include <Wire.h>
 | 
				
			||||||
#include "bsec_integration.h"
 | 
					 | 
				
			||||||
#include "irqhandler.h"
 | 
					#include "irqhandler.h"
 | 
				
			||||||
 | 
					#include "../lib/Bosch-BSEC/src/bsec.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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// --- 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};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bme_init();
 | 
					int bme_init();
 | 
				
			||||||
void bme_loop(void *pvParameters);
 | 
					void bme_loop(void *pvParameters);
 | 
				
			||||||
int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
 | 
					int checkIaqSensorStatus(void);
 | 
				
			||||||
                uint16_t len);
 | 
					 | 
				
			||||||
int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
 | 
					 | 
				
			||||||
                 uint16_t len);
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer);
 | 
					 | 
				
			||||||
void state_save(const uint8_t *state_buffer, uint32_t length);
 | 
					 | 
				
			||||||
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer);
 | 
					 | 
				
			||||||
void user_delay_ms(uint32_t period);
 | 
					 | 
				
			||||||
int64_t get_timestamp_us();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -89,6 +89,7 @@ extern uint8_t volatile channel;              // wifi channel rotation counter
 | 
				
			|||||||
extern uint16_t volatile macs_total, macs_wifi, macs_ble,
 | 
					extern uint16_t volatile macs_total, macs_wifi, macs_ble,
 | 
				
			||||||
    batt_voltage;                  // display values
 | 
					    batt_voltage;                  // display values
 | 
				
			||||||
extern hw_timer_t *channelSwitch, *sendCycle, *displaytimer;
 | 
					extern hw_timer_t *channelSwitch, *sendCycle, *displaytimer;
 | 
				
			||||||
 | 
					extern SemaphoreHandle_t I2Caccess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
 | 
					extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
 | 
				
			||||||
extern std::array<uint64_t, 0xff>::iterator it;
 | 
					extern std::array<uint64_t, 0xff>::iterator it;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,559 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2017 Robert Bosch. All Rights Reserved. 
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Disclaimer
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Common:
 | 
					 | 
				
			||||||
 * Bosch Sensortec products are developed for the consumer goods industry. They may only be used
 | 
					 | 
				
			||||||
 * within the parameters of the respective valid product data sheet.  Bosch Sensortec products are
 | 
					 | 
				
			||||||
 * provided with the express understanding that there is no warranty of fitness for a particular purpose.
 | 
					 | 
				
			||||||
 * They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
 | 
					 | 
				
			||||||
 * that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
 | 
					 | 
				
			||||||
 * Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
 | 
					 | 
				
			||||||
 * The resale and/or use of products are at the purchasers own risk and his own responsibility. The
 | 
					 | 
				
			||||||
 * examination of fitness for the intended use is the sole responsibility of the Purchaser.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
 | 
					 | 
				
			||||||
 * incidental, or consequential damages, arising from any product use not covered by the parameters of
 | 
					 | 
				
			||||||
 * the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
 | 
					 | 
				
			||||||
 * Sensortec for all costs in connection with such claims.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The purchaser must monitor the market for the purchased products, particularly with regard to
 | 
					 | 
				
			||||||
 * product safety and inform Bosch Sensortec without delay of all security relevant incidents.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
 | 
					 | 
				
			||||||
 * technical specifications of the product series. They are therefore not intended or fit for resale to third
 | 
					 | 
				
			||||||
 * parties or for use in end products. Their sole purpose is internal client testing. The testing of an
 | 
					 | 
				
			||||||
 * engineering sample may in no way replace the testing of a product series. Bosch Sensortec
 | 
					 | 
				
			||||||
 * assumes no liability for the use of engineering samples. By accepting the engineering samples, the
 | 
					 | 
				
			||||||
 * Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
 | 
					 | 
				
			||||||
 * samples.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Special:
 | 
					 | 
				
			||||||
 * This software module (hereinafter called "Software") and any information on application-sheets
 | 
					 | 
				
			||||||
 * (hereinafter called "Information") is provided free of charge for the sole purpose to support your
 | 
					 | 
				
			||||||
 * application work. The Software and Information is subject to the following terms and conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The Software is specifically designed for the exclusive use for Bosch Sensortec products by
 | 
					 | 
				
			||||||
 * personnel who have special experience and training. Do not use this Software if you do not have the
 | 
					 | 
				
			||||||
 * proper experience or training.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This Software package is provided `` as is `` and without any expressed or implied warranties,
 | 
					 | 
				
			||||||
 * including without limitation, the implied warranties of merchantability and fitness for a particular
 | 
					 | 
				
			||||||
 * purpose.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
 | 
					 | 
				
			||||||
 * of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
 | 
					 | 
				
			||||||
 * representatives and agents shall not be liable for any direct or indirect damages or injury, except as
 | 
					 | 
				
			||||||
 * otherwise stipulated in mandatory applicable law.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
 | 
					 | 
				
			||||||
 * responsibility for the consequences of use of such Information nor for any infringement of patents or
 | 
					 | 
				
			||||||
 * other rights of third parties which may result from its use. No license is granted by implication or
 | 
					 | 
				
			||||||
 * otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
 | 
					 | 
				
			||||||
 * subject to change without notice.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * It is not allowed to deliver the source code of the Software to any third party without permission of
 | 
					 | 
				
			||||||
 * Bosch Sensortec.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @file bsec_integration.c
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @brief
 | 
					 | 
				
			||||||
 * Private part of the example for using of BSEC library.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @addtogroup bsec_examples BSEC Examples
 | 
					 | 
				
			||||||
 * @brief BSEC usage examples
 | 
					 | 
				
			||||||
 * @{*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* header files */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "bsec_integration.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* local macro definitions */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define NUM_USED_OUTPUTS 8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* global variable declarations */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global sensor APIs data structure */
 | 
					 | 
				
			||||||
static struct bme680_dev bme680_g;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Global temperature offset to be subtracted */
 | 
					 | 
				
			||||||
static float bme680_temperature_offset_g = 0.0f;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* functions */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief        Virtual sensor subscription
 | 
					 | 
				
			||||||
 *               Please call this function before processing of data using bsec_do_steps function
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]    sample_rate         mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
 | 
					 | 
				
			||||||
 *  
 | 
					 | 
				
			||||||
 * @return       subscription result, zero when successful
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static bsec_library_return_t bme680_bsec_update_subscription(float sample_rate)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS];
 | 
					 | 
				
			||||||
    uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
 | 
					 | 
				
			||||||
    uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    bsec_library_return_t status = BSEC_OK;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* note: Virtual sensors as desired to be added here */
 | 
					 | 
				
			||||||
    requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[0].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[1].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[2].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[3].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_RAW_GAS;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[4].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[5].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[6].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[7].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
 | 
					 | 
				
			||||||
    requested_virtual_sensors[7].sample_rate = sample_rate;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
 | 
					 | 
				
			||||||
    status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
 | 
					 | 
				
			||||||
        &n_required_sensor_settings);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    return status;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Initialize the BME680 sensor and the BSEC library
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   sample_rate         mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
 | 
					 | 
				
			||||||
 * @param[in]   temperature_offset  device-specific temperature offset (due to self-heating)
 | 
					 | 
				
			||||||
 * @param[in]   bus_write           pointer to the bus writing function
 | 
					 | 
				
			||||||
 * @param[in]   bus_read            pointer to the bus reading function
 | 
					 | 
				
			||||||
 * @param[in]   sleep               pointer to the system specific sleep function
 | 
					 | 
				
			||||||
 * @param[in]   state_load          pointer to the system-specific state load function
 | 
					 | 
				
			||||||
 * @param[in]   config_load         pointer to the system-specific config load function
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      zero if successful, negative otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write, 
 | 
					 | 
				
			||||||
                    bme680_com_fptr_t bus_read, sleep_fct sleep, state_load_fct state_load, config_load_fct config_load)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return_values_init ret = {BME680_OK, BSEC_OK};
 | 
					 | 
				
			||||||
    bsec_library_return_t bsec_status = BSEC_OK;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    uint8_t bsec_state[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
 | 
					 | 
				
			||||||
    uint8_t bsec_config[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
 | 
					 | 
				
			||||||
    uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE] = {0};
 | 
					 | 
				
			||||||
    int bsec_state_len, bsec_config_len;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Fixed I2C configuration */
 | 
					 | 
				
			||||||
    bme680_g.dev_id = BME680_I2C_ADDR_PRIMARY;
 | 
					 | 
				
			||||||
    bme680_g.intf = BME680_I2C_INTF;
 | 
					 | 
				
			||||||
    /* User configurable I2C configuration */
 | 
					 | 
				
			||||||
    bme680_g.write = bus_write;
 | 
					 | 
				
			||||||
    bme680_g.read = bus_read;
 | 
					 | 
				
			||||||
    bme680_g.delay_ms = sleep;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Initialize BME680 API */
 | 
					 | 
				
			||||||
    ret.bme680_status = bme680_init(&bme680_g);
 | 
					 | 
				
			||||||
    if (ret.bme680_status != BME680_OK)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Initialize BSEC library */
 | 
					 | 
				
			||||||
    ret.bsec_status = bsec_init();
 | 
					 | 
				
			||||||
    if (ret.bsec_status != BSEC_OK)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Load library config, if available */
 | 
					 | 
				
			||||||
    bsec_config_len = config_load(bsec_config, sizeof(bsec_config));
 | 
					 | 
				
			||||||
    if (bsec_config_len != 0)
 | 
					 | 
				
			||||||
    {       
 | 
					 | 
				
			||||||
        ret.bsec_status = bsec_set_configuration(bsec_config, bsec_config_len, work_buffer, sizeof(work_buffer));     
 | 
					 | 
				
			||||||
        if (ret.bsec_status != BSEC_OK)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Load previous library state, if available */
 | 
					 | 
				
			||||||
    bsec_state_len = state_load(bsec_state, sizeof(bsec_state));
 | 
					 | 
				
			||||||
    if (bsec_state_len != 0)
 | 
					 | 
				
			||||||
    {       
 | 
					 | 
				
			||||||
        ret.bsec_status = bsec_set_state(bsec_state, bsec_state_len, work_buffer, sizeof(work_buffer));     
 | 
					 | 
				
			||||||
        if (ret.bsec_status != BSEC_OK)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return ret;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Set temperature offset */
 | 
					 | 
				
			||||||
    bme680_temperature_offset_g = temperature_offset;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Call to the function which sets the library with subscription information */
 | 
					 | 
				
			||||||
    ret.bsec_status = bme680_bsec_update_subscription(sample_rate);
 | 
					 | 
				
			||||||
    if (ret.bsec_status != BSEC_OK)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return ret;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Trigger the measurement based on sensor settings
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   sensor_settings     settings of the BME680 sensor adopted by sensor control function
 | 
					 | 
				
			||||||
 * @param[in]   sleep               pointer to the system specific sleep function
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      none
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void bme680_bsec_trigger_measurement(bsec_bme_settings_t *sensor_settings, sleep_fct sleep)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    uint16_t meas_period;
 | 
					 | 
				
			||||||
    uint8_t set_required_settings;
 | 
					 | 
				
			||||||
    int8_t bme680_status = BME680_OK;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    /* Check if a forced-mode measurement should be triggered now */
 | 
					 | 
				
			||||||
    if (sensor_settings->trigger_measurement)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        /* Set sensor configuration */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bme680_g.tph_sett.os_hum  = sensor_settings->humidity_oversampling;
 | 
					 | 
				
			||||||
        bme680_g.tph_sett.os_pres = sensor_settings->pressure_oversampling;
 | 
					 | 
				
			||||||
        bme680_g.tph_sett.os_temp = sensor_settings->temperature_oversampling;
 | 
					 | 
				
			||||||
        bme680_g.gas_sett.run_gas = sensor_settings->run_gas;
 | 
					 | 
				
			||||||
        bme680_g.gas_sett.heatr_temp = sensor_settings->heater_temperature; /* degree Celsius */
 | 
					 | 
				
			||||||
        bme680_g.gas_sett.heatr_dur  = sensor_settings->heating_duration; /* milliseconds */
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Select the power mode */
 | 
					 | 
				
			||||||
        /* Must be set before writing the sensor configuration */
 | 
					 | 
				
			||||||
        bme680_g.power_mode = BME680_FORCED_MODE;
 | 
					 | 
				
			||||||
        /* Set the required sensor settings needed */
 | 
					 | 
				
			||||||
        set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Set the desired sensor configuration */
 | 
					 | 
				
			||||||
        bme680_status = bme680_set_sensor_settings(set_required_settings, &bme680_g);
 | 
					 | 
				
			||||||
             
 | 
					 | 
				
			||||||
        /* Set power mode as forced mode and trigger forced mode measurement */
 | 
					 | 
				
			||||||
        bme680_status = bme680_set_sensor_mode(&bme680_g);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Get the total measurement duration so as to sleep or wait till the measurement is complete */
 | 
					 | 
				
			||||||
        bme680_get_profile_dur(&meas_period, &bme680_g);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Delay till the measurement is ready. Timestamp resolution in ms */
 | 
					 | 
				
			||||||
        sleep((uint32_t)meas_period);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Call the API to get current operation mode of the sensor */
 | 
					 | 
				
			||||||
    bme680_status = bme680_get_sensor_mode(&bme680_g);  
 | 
					 | 
				
			||||||
    /* When the measurement is completed and data is ready for reading, the sensor must be in BME680_SLEEP_MODE.
 | 
					 | 
				
			||||||
     * Read operation mode to check whether measurement is completely done and wait until the sensor is no more
 | 
					 | 
				
			||||||
     * in BME680_FORCED_MODE. */
 | 
					 | 
				
			||||||
    while (bme680_g.power_mode == BME680_FORCED_MODE)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        /* sleep for 5 ms */
 | 
					 | 
				
			||||||
        sleep(5);
 | 
					 | 
				
			||||||
        bme680_status = bme680_get_sensor_mode(&bme680_g);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Read the data from registers and populate the inputs structure to be passed to do_steps function
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   time_stamp_trigger      settings of the sensor returned from sensor control function
 | 
					 | 
				
			||||||
 * @param[in]   inputs                  input structure containing the information on sensors to be passed to do_steps
 | 
					 | 
				
			||||||
 * @param[in]   num_bsec_inputs         number of inputs to be passed to do_steps
 | 
					 | 
				
			||||||
 * @param[in]   bsec_process_data       process data variable returned from sensor_control
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      none
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void bme680_bsec_read_data(int64_t time_stamp_trigger, bsec_input_t *inputs, uint8_t *num_bsec_inputs,
 | 
					 | 
				
			||||||
    int32_t bsec_process_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    static struct bme680_field_data data;
 | 
					 | 
				
			||||||
    int8_t bme680_status = BME680_OK;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* We only have to read data if the previous call the bsec_sensor_control() actually asked for it */
 | 
					 | 
				
			||||||
    if (bsec_process_data)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        bme680_status = bme680_get_sensor_data(&data, &bme680_g);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (data.status & BME680_NEW_DATA_MSK)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            /* Pressure to be processed by BSEC */
 | 
					 | 
				
			||||||
            if (bsec_process_data & BSEC_PROCESS_PRESSURE)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                /* Place presssure sample into input struct */
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].signal = data.pressure;
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
 | 
					 | 
				
			||||||
                (*num_bsec_inputs)++;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            /* Temperature to be processed by BSEC */
 | 
					 | 
				
			||||||
            if (bsec_process_data & BSEC_PROCESS_TEMPERATURE)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                /* Place temperature sample into input struct */
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
 | 
					 | 
				
			||||||
                #ifdef BME680_FLOAT_POINT_COMPENSATION
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].signal = data.temperature;
 | 
					 | 
				
			||||||
                #else
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].signal = data.temperature / 100.0f;
 | 
					 | 
				
			||||||
                #endif
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
 | 
					 | 
				
			||||||
                (*num_bsec_inputs)++;
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                /* Also add optional heatsource input which will be subtracted from the temperature reading to 
 | 
					 | 
				
			||||||
                 * compensate for device-specific self-heating (supported in BSEC IAQ solution)*/
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].signal = bme680_temperature_offset_g;
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
 | 
					 | 
				
			||||||
                (*num_bsec_inputs)++;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            /* Humidity to be processed by BSEC */
 | 
					 | 
				
			||||||
            if (bsec_process_data & BSEC_PROCESS_HUMIDITY)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                /* Place humidity sample into input struct */
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
 | 
					 | 
				
			||||||
                #ifdef BME680_FLOAT_POINT_COMPENSATION
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].signal = data.humidity;
 | 
					 | 
				
			||||||
                #else
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].signal = data.humidity / 1000.0f;
 | 
					 | 
				
			||||||
                #endif  
 | 
					 | 
				
			||||||
                inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
 | 
					 | 
				
			||||||
                (*num_bsec_inputs)++;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            /* Gas to be processed by BSEC */
 | 
					 | 
				
			||||||
            if (bsec_process_data & BSEC_PROCESS_GAS)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                /* Check whether gas_valid flag is set */
 | 
					 | 
				
			||||||
                if(data.status & BME680_GASM_VALID_MSK)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    /* Place sample into input struct */
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].signal = data.gas_resistance;
 | 
					 | 
				
			||||||
                    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
 | 
					 | 
				
			||||||
                    (*num_bsec_inputs)++;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       This function is written to process the sensor data for the requested virtual sensors
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   bsec_inputs         input structure containing the information on sensors to be passed to do_steps
 | 
					 | 
				
			||||||
 * @param[in]   num_bsec_inputs     number of inputs to be passed to do_steps
 | 
					 | 
				
			||||||
 * @param[in]   output_ready        pointer to the function processing obtained BSEC outputs
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      none
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void bme680_bsec_process_data(bsec_input_t *bsec_inputs, uint8_t num_bsec_inputs, output_ready_fct output_ready)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Output buffer set to the maximum virtual sensor outputs supported */
 | 
					 | 
				
			||||||
    bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
 | 
					 | 
				
			||||||
    uint8_t num_bsec_outputs = 0;
 | 
					 | 
				
			||||||
    uint8_t index = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bsec_library_return_t bsec_status = BSEC_OK;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    int64_t timestamp = 0;
 | 
					 | 
				
			||||||
    float iaq = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t iaq_accuracy = 0;
 | 
					 | 
				
			||||||
    float temp = 0.0f;
 | 
					 | 
				
			||||||
    float raw_temp = 0.0f;
 | 
					 | 
				
			||||||
    float raw_pressure = 0.0f;
 | 
					 | 
				
			||||||
    float humidity = 0.0f;
 | 
					 | 
				
			||||||
    float raw_humidity = 0.0f;
 | 
					 | 
				
			||||||
    float raw_gas = 0.0f;
 | 
					 | 
				
			||||||
    float static_iaq = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t static_iaq_accuracy = 0;
 | 
					 | 
				
			||||||
    float co2_equivalent = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t co2_accuracy = 0;
 | 
					 | 
				
			||||||
    float breath_voc_equivalent = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t breath_voc_accuracy = 0;
 | 
					 | 
				
			||||||
    float comp_gas_value = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t comp_gas_accuracy = 0;
 | 
					 | 
				
			||||||
    float gas_percentage = 0.0f;
 | 
					 | 
				
			||||||
    uint8_t gas_percentage_acccuracy = 0;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Check if something should be processed by BSEC */
 | 
					 | 
				
			||||||
    if (num_bsec_inputs > 0)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        /* Set number of outputs to the size of the allocated buffer */
 | 
					 | 
				
			||||||
        /* BSEC_NUMBER_OUTPUTS to be defined */
 | 
					 | 
				
			||||||
        num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Perform processing of the data by BSEC 
 | 
					 | 
				
			||||||
           Note:
 | 
					 | 
				
			||||||
           * The number of outputs you get depends on what you asked for during bsec_update_subscription(). This is
 | 
					 | 
				
			||||||
             handled under bme680_bsec_update_subscription() function in this example file.
 | 
					 | 
				
			||||||
           * The number of actual outputs that are returned is written to num_bsec_outputs. */
 | 
					 | 
				
			||||||
        bsec_status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Iterate through the outputs and extract the relevant ones. */
 | 
					 | 
				
			||||||
        for (index = 0; index < num_bsec_outputs; index++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            switch (bsec_outputs[index].sensor_id)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_IAQ:
 | 
					 | 
				
			||||||
                    iaq = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    iaq_accuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_STATIC_IAQ:
 | 
					 | 
				
			||||||
                    static_iaq = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    static_iaq_accuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_CO2_EQUIVALENT:
 | 
					 | 
				
			||||||
                    co2_equivalent = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    co2_accuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
 | 
					 | 
				
			||||||
                    breath_voc_equivalent = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    breath_voc_accuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
 | 
					 | 
				
			||||||
                    temp = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_RAW_PRESSURE:
 | 
					 | 
				
			||||||
                    raw_pressure = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
 | 
					 | 
				
			||||||
                    humidity = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_RAW_GAS:
 | 
					 | 
				
			||||||
                    raw_gas = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_RAW_TEMPERATURE:
 | 
					 | 
				
			||||||
                    raw_temp = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_RAW_HUMIDITY:
 | 
					 | 
				
			||||||
                    raw_humidity = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_COMPENSATED_GAS:
 | 
					 | 
				
			||||||
                    comp_gas_value = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    comp_gas_accuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case BSEC_OUTPUT_GAS_PERCENTAGE:
 | 
					 | 
				
			||||||
                    gas_percentage = bsec_outputs[index].signal;
 | 
					 | 
				
			||||||
                    gas_percentage_acccuracy = bsec_outputs[index].accuracy;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                default:
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            /* Assume that all the returned timestamps are the same */
 | 
					 | 
				
			||||||
            timestamp = bsec_outputs[index].time_stamp;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Pass the extracted outputs to the user provided output_ready() function. */
 | 
					 | 
				
			||||||
        output_ready(timestamp, iaq, iaq_accuracy, temp, humidity, raw_pressure, raw_temp, 
 | 
					 | 
				
			||||||
            raw_humidity, raw_gas, bsec_status, static_iaq, co2_equivalent, breath_voc_equivalent);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   sleep               pointer to the system specific sleep function
 | 
					 | 
				
			||||||
 * @param[in]   get_timestamp_us    pointer to the system specific timestamp derivation function
 | 
					 | 
				
			||||||
 * @param[in]   output_ready        pointer to the function processing obtained BSEC outputs
 | 
					 | 
				
			||||||
 * @param[in]   state_save          pointer to the system-specific state save function
 | 
					 | 
				
			||||||
 * @param[in]   save_intvl          interval at which BSEC state should be saved (in samples)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      none
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
 | 
					 | 
				
			||||||
                    state_save_fct state_save, uint32_t save_intvl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* Timestamp variables */
 | 
					 | 
				
			||||||
    int64_t time_stamp = 0;
 | 
					 | 
				
			||||||
    int64_t time_stamp_interval_ms = 0;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Allocate enough memory for up to BSEC_MAX_PHYSICAL_SENSOR physical inputs*/
 | 
					 | 
				
			||||||
    bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Number of inputs to BSEC */
 | 
					 | 
				
			||||||
    uint8_t num_bsec_inputs = 0;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* BSEC sensor settings struct */
 | 
					 | 
				
			||||||
    bsec_bme_settings_t sensor_settings;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    /* Save state variables */
 | 
					 | 
				
			||||||
    uint8_t bsec_state[BSEC_MAX_STATE_BLOB_SIZE];
 | 
					 | 
				
			||||||
    uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
 | 
					 | 
				
			||||||
    uint32_t bsec_state_len = 0;
 | 
					 | 
				
			||||||
    uint32_t n_samples = 0;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    bsec_library_return_t bsec_status = BSEC_OK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (1)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        /* get the timestamp in nanoseconds before calling bsec_sensor_control() */
 | 
					 | 
				
			||||||
        time_stamp = get_timestamp_us() * 1000;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control */
 | 
					 | 
				
			||||||
        bsec_sensor_control(time_stamp, &sensor_settings);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Trigger a measurement if necessary */
 | 
					 | 
				
			||||||
        bme680_bsec_trigger_measurement(&sensor_settings, sleep);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Read data from last measurement */
 | 
					 | 
				
			||||||
        num_bsec_inputs = 0;
 | 
					 | 
				
			||||||
        bme680_bsec_read_data(time_stamp, bsec_inputs, &num_bsec_inputs, sensor_settings.process_data);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Time to invoke BSEC to perform the actual processing */
 | 
					 | 
				
			||||||
        bme680_bsec_process_data(bsec_inputs, num_bsec_inputs, output_ready);
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Increment sample counter */
 | 
					 | 
				
			||||||
        n_samples++;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Retrieve and store state if the passed save_intvl */
 | 
					 | 
				
			||||||
        if (n_samples >= save_intvl)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            bsec_status = bsec_get_state(0, bsec_state, sizeof(bsec_state), work_buffer, sizeof(work_buffer), &bsec_state_len);
 | 
					 | 
				
			||||||
            if (bsec_status == BSEC_OK)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                state_save(bsec_state, bsec_state_len);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            n_samples = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        /* Compute how long we can sleep until we need to call bsec_sensor_control() next */
 | 
					 | 
				
			||||||
        /* Time_stamp is converted from microseconds to nanoseconds first and then the difference to milliseconds */
 | 
					 | 
				
			||||||
        time_stamp_interval_ms = (sensor_settings.next_call - get_timestamp_us() * 1000) / 1000000;
 | 
					 | 
				
			||||||
        if (time_stamp_interval_ms > 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            sleep((uint32_t)time_stamp_interval_ms);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! @}*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -1,165 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (C) 2017 Robert Bosch. All Rights Reserved. 
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Disclaimer
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Common:
 | 
					 | 
				
			||||||
 * Bosch Sensortec products are developed for the consumer goods industry. They may only be used
 | 
					 | 
				
			||||||
 * within the parameters of the respective valid product data sheet.  Bosch Sensortec products are
 | 
					 | 
				
			||||||
 * provided with the express understanding that there is no warranty of fitness for a particular purpose.
 | 
					 | 
				
			||||||
 * They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
 | 
					 | 
				
			||||||
 * that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
 | 
					 | 
				
			||||||
 * Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
 | 
					 | 
				
			||||||
 * The resale and/or use of products are at the purchasers own risk and his own responsibility. The
 | 
					 | 
				
			||||||
 * examination of fitness for the intended use is the sole responsibility of the Purchaser.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
 | 
					 | 
				
			||||||
 * incidental, or consequential damages, arising from any product use not covered by the parameters of
 | 
					 | 
				
			||||||
 * the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
 | 
					 | 
				
			||||||
 * Sensortec for all costs in connection with such claims.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The purchaser must monitor the market for the purchased products, particularly with regard to
 | 
					 | 
				
			||||||
 * product safety and inform Bosch Sensortec without delay of all security relevant incidents.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
 | 
					 | 
				
			||||||
 * technical specifications of the product series. They are therefore not intended or fit for resale to third
 | 
					 | 
				
			||||||
 * parties or for use in end products. Their sole purpose is internal client testing. The testing of an
 | 
					 | 
				
			||||||
 * engineering sample may in no way replace the testing of a product series. Bosch Sensortec
 | 
					 | 
				
			||||||
 * assumes no liability for the use of engineering samples. By accepting the engineering samples, the
 | 
					 | 
				
			||||||
 * Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
 | 
					 | 
				
			||||||
 * samples.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Special:
 | 
					 | 
				
			||||||
 * This software module (hereinafter called "Software") and any information on application-sheets
 | 
					 | 
				
			||||||
 * (hereinafter called "Information") is provided free of charge for the sole purpose to support your
 | 
					 | 
				
			||||||
 * application work. The Software and Information is subject to the following terms and conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The Software is specifically designed for the exclusive use for Bosch Sensortec products by
 | 
					 | 
				
			||||||
 * personnel who have special experience and training. Do not use this Software if you do not have the
 | 
					 | 
				
			||||||
 * proper experience or training.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This Software package is provided `` as is `` and without any expressed or implied warranties,
 | 
					 | 
				
			||||||
 * including without limitation, the implied warranties of merchantability and fitness for a particular
 | 
					 | 
				
			||||||
 * purpose.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
 | 
					 | 
				
			||||||
 * of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
 | 
					 | 
				
			||||||
 * representatives and agents shall not be liable for any direct or indirect damages or injury, except as
 | 
					 | 
				
			||||||
 * otherwise stipulated in mandatory applicable law.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
 | 
					 | 
				
			||||||
 * responsibility for the consequences of use of such Information nor for any infringement of patents or
 | 
					 | 
				
			||||||
 * other rights of third parties which may result from its use. No license is granted by implication or
 | 
					 | 
				
			||||||
 * otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
 | 
					 | 
				
			||||||
 * subject to change without notice.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * It is not allowed to deliver the source code of the Software to any third party without permission of
 | 
					 | 
				
			||||||
 * Bosch Sensortec.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @file bsec_integration.h
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @brief
 | 
					 | 
				
			||||||
 * Contains BSEC integration API
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @addtogroup bsec_examples BSEC Examples
 | 
					 | 
				
			||||||
 * @brief BSEC usage examples
 | 
					 | 
				
			||||||
 * @{*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef __BSEC_INTEGRATION_H__
 | 
					 | 
				
			||||||
#define __BSEC_INTEGRATION_H__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus
 | 
					 | 
				
			||||||
extern "C"
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* header files */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Use the following bme680 driver: https://github.com/BoschSensortec/BME680_driver/releases/tag/bme680_v3.5.1 */
 | 
					 | 
				
			||||||
#include "bme680.h"
 | 
					 | 
				
			||||||
/* BSEC header files are available in the inc/ folder of the release package */
 | 
					 | 
				
			||||||
#include "bsec_interface.h"
 | 
					 | 
				
			||||||
#include "bsec_datatypes.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* type definitions */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the system specific sleep function */
 | 
					 | 
				
			||||||
typedef void (*sleep_fct)(uint32_t t_ms);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the system specific timestamp derivation function */
 | 
					 | 
				
			||||||
typedef int64_t (*get_timestamp_us_fct)();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the function processing obtained BSEC outputs */
 | 
					 | 
				
			||||||
typedef void (*output_ready_fct)(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
 | 
					 | 
				
			||||||
     float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
 | 
					 | 
				
			||||||
     float static_iaq, float co2_equivalent, float breath_voc_equivalent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the function loading a previous BSEC state from NVM */
 | 
					 | 
				
			||||||
typedef uint32_t (*state_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the function saving BSEC state to NVM */
 | 
					 | 
				
			||||||
typedef void (*state_save_fct)(const uint8_t *state_buffer, uint32_t length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* function pointer to the function loading the BSEC configuration string from NVM */
 | 
					 | 
				
			||||||
typedef uint32_t (*config_load_fct)(uint8_t *state_buffer, uint32_t n_buffer);
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
/* structure definitions */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Structure with the return value from bsec_iot_init() */
 | 
					 | 
				
			||||||
typedef struct{
 | 
					 | 
				
			||||||
	/*! Result of API execution status */
 | 
					 | 
				
			||||||
	int8_t bme680_status;
 | 
					 | 
				
			||||||
	/*! Result of BSEC library */
 | 
					 | 
				
			||||||
	bsec_library_return_t bsec_status;
 | 
					 | 
				
			||||||
}return_values_init;
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
/* function declarations */
 | 
					 | 
				
			||||||
/**********************************************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Initialize the BME680 sensor and the BSEC library
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   sample_rate         mode to be used (either BSEC_SAMPLE_RATE_ULP or BSEC_SAMPLE_RATE_LP)
 | 
					 | 
				
			||||||
 * @param[in]   temperature_offset  device-specific temperature offset (due to self-heating)
 | 
					 | 
				
			||||||
 * @param[in]   bus_write           pointer to the bus writing function
 | 
					 | 
				
			||||||
 * @param[in]   bus_read            pointer to the bus reading function
 | 
					 | 
				
			||||||
 * @param[in]   sleep               pointer to the system-specific sleep function
 | 
					 | 
				
			||||||
 * @param[in]   state_load          pointer to the system-specific state load function
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      zero if successful, negative otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
return_values_init bsec_iot_init(float sample_rate, float temperature_offset, bme680_com_fptr_t bus_write, bme680_com_fptr_t bus_read, 
 | 
					 | 
				
			||||||
    sleep_fct sleep, state_load_fct state_load, config_load_fct config_load);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @brief       Runs the main (endless) loop that queries sensor settings, applies them, and processes the measured data
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param[in]   sleep               pointer to the system-specific sleep function
 | 
					 | 
				
			||||||
 * @param[in]   get_timestamp_us    pointer to the system-specific timestamp derivation function
 | 
					 | 
				
			||||||
 * @param[in]   output_ready        pointer to the function processing obtained BSEC outputs
 | 
					 | 
				
			||||||
 * @param[in]   state_save          pointer to the system-specific state save function
 | 
					 | 
				
			||||||
 * @param[in]   save_intvl          interval at which BSEC state should be saved (in samples)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @return      return_values_init	struct with the result of the API and the BSEC library
 | 
					 | 
				
			||||||
 */ 
 | 
					 | 
				
			||||||
void bsec_iot_loop(sleep_fct sleep, get_timestamp_us_fct get_timestamp_us, output_ready_fct output_ready,
 | 
					 | 
				
			||||||
    state_save_fct state_save, uint32_t save_intvl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __cplusplus
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* __BSEC_INTEGRATION_H__ */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*! @}*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -103,7 +103,7 @@
 | 
				
			|||||||
/** BME680 configuration macros */
 | 
					/** BME680 configuration macros */
 | 
				
			||||||
/** Enable or un-comment the macro to provide floating point data output */
 | 
					/** Enable or un-comment the macro to provide floating point data output */
 | 
				
			||||||
#ifndef BME680_FLOAT_POINT_COMPENSATION
 | 
					#ifndef BME680_FLOAT_POINT_COMPENSATION
 | 
				
			||||||
/* #define BME680_FLOAT_POINT_COMPENSATION */
 | 
					//#define BME680_FLOAT_POINT_COMPENSATION
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** BME680 General config */
 | 
					/** BME680 General config */
 | 
				
			||||||
							
								
								
									
										498
									
								
								lib/Bosch-BSEC/src/bsec.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										498
									
								
								lib/Bosch-BSEC/src/bsec.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,498 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 * notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 * notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 * documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Neither the name of the copyright holder nor the names of the
 | 
				
			||||||
 | 
					 * contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					 * this software without specific prior written permission.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
				
			||||||
 | 
					 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					 * OR CONTRIBUTORS BE LIABLE FOR ANY
 | 
				
			||||||
 | 
					 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 | 
				
			||||||
 | 
					 * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
 | 
				
			||||||
 | 
					 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
				
			||||||
 | 
					 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
				
			||||||
 | 
					 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
				
			||||||
 | 
					 * ANY WAY OUT OF THE USE OF THIS
 | 
				
			||||||
 | 
					 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The information provided is believed to be accurate and reliable.
 | 
				
			||||||
 | 
					 * The copyright holder 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 the copyright holder.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @file	bsec.cpp
 | 
				
			||||||
 | 
					 * @date	31 Jan 2018
 | 
				
			||||||
 | 
					 * @version	1.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "bsec.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TwoWire *Bsec::wireObj = NULL;
 | 
				
			||||||
 | 
					SPIClass *Bsec::spiObj = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Constructor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Bsec::Bsec() {
 | 
				
			||||||
 | 
					  nextCall = 0;
 | 
				
			||||||
 | 
					  version.major = 0;
 | 
				
			||||||
 | 
					  version.minor = 0;
 | 
				
			||||||
 | 
					  version.major_bugfix = 0;
 | 
				
			||||||
 | 
					  version.minor_bugfix = 0;
 | 
				
			||||||
 | 
					  millisOverflowCounter = 0;
 | 
				
			||||||
 | 
					  lastTime = 0;
 | 
				
			||||||
 | 
					  bme680Status = BME680_OK;
 | 
				
			||||||
 | 
					  outputTimestamp = 0;
 | 
				
			||||||
 | 
					  _tempOffset = 0.0f;
 | 
				
			||||||
 | 
					  status = BSEC_OK;
 | 
				
			||||||
 | 
					  zeroOutputs();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read,
 | 
				
			||||||
 | 
					                 bme680_com_fptr_t write, bme680_delay_fptr_t idleTask) {
 | 
				
			||||||
 | 
					  _bme680.dev_id = devId;
 | 
				
			||||||
 | 
					  _bme680.intf = intf;
 | 
				
			||||||
 | 
					  _bme680.read = read;
 | 
				
			||||||
 | 
					  _bme680.write = write;
 | 
				
			||||||
 | 
					  _bme680.delay_ms = idleTask;
 | 
				
			||||||
 | 
					  _bme680.amb_temp = 25;
 | 
				
			||||||
 | 
					  _bme680.power_mode = BME680_FORCED_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beginCommon();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c) {
 | 
				
			||||||
 | 
					  _bme680.dev_id = i2cAddr;
 | 
				
			||||||
 | 
					  _bme680.intf = BME680_I2C_INTF;
 | 
				
			||||||
 | 
					  _bme680.read = Bsec::i2cRead;
 | 
				
			||||||
 | 
					  _bme680.write = Bsec::i2cWrite;
 | 
				
			||||||
 | 
					  _bme680.delay_ms = Bsec::delay_ms;
 | 
				
			||||||
 | 
					  _bme680.amb_temp = 25;
 | 
				
			||||||
 | 
					  _bme680.power_mode = BME680_FORCED_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Bsec::wireObj = &i2c;
 | 
				
			||||||
 | 
					  Bsec::wireObj->begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beginCommon();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::begin(uint8_t chipSelect, SPIClass &spi) {
 | 
				
			||||||
 | 
					  _bme680.dev_id = chipSelect;
 | 
				
			||||||
 | 
					  _bme680.intf = BME680_SPI_INTF;
 | 
				
			||||||
 | 
					  _bme680.read = Bsec::spiTransfer;
 | 
				
			||||||
 | 
					  _bme680.write = Bsec::spiTransfer;
 | 
				
			||||||
 | 
					  _bme680.delay_ms = Bsec::delay_ms;
 | 
				
			||||||
 | 
					  _bme680.amb_temp = 25;
 | 
				
			||||||
 | 
					  _bme680.power_mode = BME680_FORCED_MODE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pinMode(chipSelect, OUTPUT);
 | 
				
			||||||
 | 
					  digitalWrite(chipSelect, HIGH);
 | 
				
			||||||
 | 
					  Bsec::spiObj = &spi;
 | 
				
			||||||
 | 
					  Bsec::spiObj->begin();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beginCommon();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Common code for the begin function
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::beginCommon(void) {
 | 
				
			||||||
 | 
					  status = bsec_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getVersion();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bme680Status = bme680_init(&_bme680);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function that sets the desired sensors and the sample rates
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[],
 | 
				
			||||||
 | 
					                              uint8_t nSensors, float sampleRate) {
 | 
				
			||||||
 | 
					  bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS],
 | 
				
			||||||
 | 
					      sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
 | 
				
			||||||
 | 
					  uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (uint8_t i = 0; i < nSensors; i++) {
 | 
				
			||||||
 | 
					    virtualSensors[nVirtualSensors].sensor_id = sensorList[i];
 | 
				
			||||||
 | 
					    virtualSensors[nVirtualSensors].sample_rate = sampleRate;
 | 
				
			||||||
 | 
					    nVirtualSensors++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  status = bsec_update_subscription(virtualSensors, nVirtualSensors,
 | 
				
			||||||
 | 
					                                    sensorSettings, &nSensorSettings);
 | 
				
			||||||
 | 
					  return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Callback from the user to trigger reading of data from the BME680,
 | 
				
			||||||
 | 
					 * process and store outputs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool Bsec::run(void) {
 | 
				
			||||||
 | 
					  bool newData = false;
 | 
				
			||||||
 | 
					  /* Check if the time has arrived to call do_steps() */
 | 
				
			||||||
 | 
					  int64_t callTimeMs = getTimeMs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (callTimeMs >= nextCall) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bsec_bme_settings_t bme680Settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int64_t callTimeNs = callTimeMs * INT64_C(1000000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = bsec_sensor_control(callTimeNs, &bme680Settings);
 | 
				
			||||||
 | 
					    if (status < BSEC_OK)
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nextCall =
 | 
				
			||||||
 | 
					        bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bme680Status = setBme680Config(bme680Settings);
 | 
				
			||||||
 | 
					    if (bme680Status != BME680_OK) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bme680Status = bme680_set_sensor_mode(&_bme680);
 | 
				
			||||||
 | 
					    if (bme680Status != BME680_OK) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Wait for measurement to complete */
 | 
				
			||||||
 | 
					    uint16_t meas_dur = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bme680_get_profile_dur(&meas_dur, &_bme680);
 | 
				
			||||||
 | 
					    delay_ms(meas_dur);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newData = readProcessData(callTimeNs, bme680Settings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return newData;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to get the state of the algorithm to save to non-volatile
 | 
				
			||||||
 | 
					 * memory
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::getState(uint8_t *state) {
 | 
				
			||||||
 | 
					  uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
 | 
				
			||||||
 | 
					  uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
 | 
				
			||||||
 | 
					  status = bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer,
 | 
				
			||||||
 | 
					                          BSEC_MAX_STATE_BLOB_SIZE, &n_serialized_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to set the state of the algorithm from non-volatile memory
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::setState(uint8_t *state) {
 | 
				
			||||||
 | 
					  uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer,
 | 
				
			||||||
 | 
					                          BSEC_MAX_STATE_BLOB_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to set the configuration of the algorithm from memory
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::setConfig(const uint8_t *state) {
 | 
				
			||||||
 | 
					  uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE,
 | 
				
			||||||
 | 
					                                  workBuffer, sizeof(workBuffer));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Private functions */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Get the version of the BSEC library
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::getVersion(void) { bsec_get_version(&version); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Read data from the BME680 and process it
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool Bsec::readProcessData(int64_t currTimeNs,
 | 
				
			||||||
 | 
					                           bsec_bme_settings_t bme680Settings) {
 | 
				
			||||||
 | 
					  bme680Status = bme680_get_sensor_data(&_data, &_bme680);
 | 
				
			||||||
 | 
					  if (bme680Status != BME680_OK) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temp, Pres, Hum & Gas
 | 
				
			||||||
 | 
					  uint8_t nInputs = 0, nOutputs = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (_data.status & BME680_NEW_DATA_MSK) {
 | 
				
			||||||
 | 
					    if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) {
 | 
				
			||||||
 | 
					      inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
 | 
				
			||||||
 | 
					#ifdef BME680_FLOAT_POINT_COMPENSATION
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.temperature;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.temperature / 100.0f;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      inputs[nInputs].time_stamp = currTimeNs;
 | 
				
			||||||
 | 
					      nInputs++;
 | 
				
			||||||
 | 
					      /* Temperature offset from the real temperature due to external heat
 | 
				
			||||||
 | 
					       * sources */
 | 
				
			||||||
 | 
					      inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _tempOffset;
 | 
				
			||||||
 | 
					      inputs[nInputs].time_stamp = currTimeNs;
 | 
				
			||||||
 | 
					      nInputs++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) {
 | 
				
			||||||
 | 
					      inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
 | 
				
			||||||
 | 
					#ifdef BME680_FLOAT_POINT_COMPENSATION
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.humidity;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.humidity / 1000.0f;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      inputs[nInputs].time_stamp = currTimeNs;
 | 
				
			||||||
 | 
					      nInputs++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE) {
 | 
				
			||||||
 | 
					      inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.pressure;
 | 
				
			||||||
 | 
					      inputs[nInputs].time_stamp = currTimeNs;
 | 
				
			||||||
 | 
					      nInputs++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (bme680Settings.process_data & BSEC_PROCESS_GAS) {
 | 
				
			||||||
 | 
					      inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
 | 
				
			||||||
 | 
					      inputs[nInputs].signal = _data.gas_resistance;
 | 
				
			||||||
 | 
					      inputs[nInputs].time_stamp = currTimeNs;
 | 
				
			||||||
 | 
					      nInputs++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (nInputs > 0) {
 | 
				
			||||||
 | 
					    nOutputs = BSEC_NUMBER_OUTPUTS;
 | 
				
			||||||
 | 
					    bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs);
 | 
				
			||||||
 | 
					    if (status != BSEC_OK)
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    zeroOutputs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nOutputs > 0) {
 | 
				
			||||||
 | 
					      outputTimestamp =
 | 
				
			||||||
 | 
					          _outputs[0].time_stamp / 1000000; // Convert from ns to ms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (uint8_t i = 0; i < nOutputs; i++) {
 | 
				
			||||||
 | 
					        switch (_outputs[i].sensor_id) {
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_IAQ:
 | 
				
			||||||
 | 
					          iaqEstimate = _outputs[i].signal;
 | 
				
			||||||
 | 
					          iaqAccuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_STATIC_IAQ:
 | 
				
			||||||
 | 
					          staticIaq = _outputs[i].signal;
 | 
				
			||||||
 | 
					          staticIaqAccuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_CO2_EQUIVALENT:
 | 
				
			||||||
 | 
					          co2Equivalent = _outputs[i].signal;
 | 
				
			||||||
 | 
					          co2Accuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
 | 
				
			||||||
 | 
					          breathVocEquivalent = _outputs[i].signal;
 | 
				
			||||||
 | 
					          breathVocAccuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_RAW_TEMPERATURE:
 | 
				
			||||||
 | 
					          rawTemperature = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_RAW_PRESSURE:
 | 
				
			||||||
 | 
					          pressure = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_RAW_HUMIDITY:
 | 
				
			||||||
 | 
					          rawHumidity = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_RAW_GAS:
 | 
				
			||||||
 | 
					          gasResistance = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_STABILIZATION_STATUS:
 | 
				
			||||||
 | 
					          stabStatus = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_RUN_IN_STATUS:
 | 
				
			||||||
 | 
					          runInStatus = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
 | 
				
			||||||
 | 
					          temperature = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
 | 
				
			||||||
 | 
					          humidity = _outputs[i].signal;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_COMPENSATED_GAS:
 | 
				
			||||||
 | 
					          compGasValue = _outputs[i].signal;
 | 
				
			||||||
 | 
					          compGasAccuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case BSEC_OUTPUT_GAS_PERCENTAGE:
 | 
				
			||||||
 | 
					          gasPercentage = _outputs[i].signal;
 | 
				
			||||||
 | 
					          gasPercentageAcccuracy = _outputs[i].accuracy;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Set the BME680 sensor's configuration
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) {
 | 
				
			||||||
 | 
					  _bme680.gas_sett.run_gas = bme680Settings.run_gas;
 | 
				
			||||||
 | 
					  _bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling;
 | 
				
			||||||
 | 
					  _bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling;
 | 
				
			||||||
 | 
					  _bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling;
 | 
				
			||||||
 | 
					  _bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature;
 | 
				
			||||||
 | 
					  _bme680.gas_sett.heatr_dur = bme680Settings.heating_duration;
 | 
				
			||||||
 | 
					  uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL |
 | 
				
			||||||
 | 
					                              BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
 | 
				
			||||||
 | 
					  return bme680_set_sensor_settings(desired_settings, &_bme680);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to zero the outputs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::zeroOutputs(void) {
 | 
				
			||||||
 | 
					  temperature = 0.0f;
 | 
				
			||||||
 | 
					  pressure = 0.0f;
 | 
				
			||||||
 | 
					  humidity = 0.0f;
 | 
				
			||||||
 | 
					  gasResistance = 0.0f;
 | 
				
			||||||
 | 
					  rawTemperature = 0.0f;
 | 
				
			||||||
 | 
					  rawHumidity = 0.0f;
 | 
				
			||||||
 | 
					  stabStatus = 0.0f;
 | 
				
			||||||
 | 
					  runInStatus = 0.0f;
 | 
				
			||||||
 | 
					  iaqEstimate = 0.0f;
 | 
				
			||||||
 | 
					  iaqAccuracy = 0;
 | 
				
			||||||
 | 
					  staticIaq = 0.0f;
 | 
				
			||||||
 | 
					  staticIaqAccuracy = 0;
 | 
				
			||||||
 | 
					  co2Equivalent = 0.0f;
 | 
				
			||||||
 | 
					  co2Accuracy = 0;
 | 
				
			||||||
 | 
					  breathVocEquivalent = 0.0f;
 | 
				
			||||||
 | 
					  breathVocAccuracy = 0;
 | 
				
			||||||
 | 
					  compGasValue = 0.0f;
 | 
				
			||||||
 | 
					  compGasAccuracy = 0;
 | 
				
			||||||
 | 
					  gasPercentage = 0.0f;
 | 
				
			||||||
 | 
					  gasPercentageAcccuracy = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Function to calculate an int64_t timestamp in milliseconds
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int64_t Bsec::getTimeMs(void) {
 | 
				
			||||||
 | 
					  int64_t timeMs = millis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (lastTime > timeMs) { // An overflow occured
 | 
				
			||||||
 | 
					    lastTime = timeMs;
 | 
				
			||||||
 | 
					    millisOverflowCounter++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return timeMs + (millisOverflowCounter * 0xFFFFFFFF);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 @brief Task that delays for a ms period of time
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void Bsec::delay_ms(uint32_t period) {
 | 
				
			||||||
 | 
					  // Wait for a period amount of ms
 | 
				
			||||||
 | 
					  // The system may simply idle, sleep or even perform background tasks
 | 
				
			||||||
 | 
					  delay(period);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 @brief Callback function for reading registers over I2C
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData,
 | 
				
			||||||
 | 
					                     uint16_t length) {
 | 
				
			||||||
 | 
					  uint16_t i;
 | 
				
			||||||
 | 
					  int8_t rslt = 0;
 | 
				
			||||||
 | 
					  if (Bsec::wireObj) {
 | 
				
			||||||
 | 
					    Bsec::wireObj->beginTransmission(devId);
 | 
				
			||||||
 | 
					    Bsec::wireObj->write(regAddr);
 | 
				
			||||||
 | 
					    rslt = Bsec::wireObj->endTransmission();
 | 
				
			||||||
 | 
					    Bsec::wireObj->requestFrom((int)devId, (int)length);
 | 
				
			||||||
 | 
					    for (i = 0; (i < length) && Bsec::wireObj->available(); i++) {
 | 
				
			||||||
 | 
					      regData[i] = Bsec::wireObj->read();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    rslt = -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return rslt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Callback function for writing registers over I2C
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData,
 | 
				
			||||||
 | 
					                      uint16_t length) {
 | 
				
			||||||
 | 
					  uint16_t i;
 | 
				
			||||||
 | 
					  int8_t rslt = 0;
 | 
				
			||||||
 | 
					  if (Bsec::wireObj) {
 | 
				
			||||||
 | 
					    Bsec::wireObj->beginTransmission(devId);
 | 
				
			||||||
 | 
					    Bsec::wireObj->write(regAddr);
 | 
				
			||||||
 | 
					    for (i = 0; i < length; i++) {
 | 
				
			||||||
 | 
					      Bsec::wireObj->write(regData[i]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rslt = Bsec::wireObj->endTransmission();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    rslt = -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rslt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Callback function for reading and writing registers over SPI
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData,
 | 
				
			||||||
 | 
					                         uint16_t length) {
 | 
				
			||||||
 | 
					  int8_t rslt = 0;
 | 
				
			||||||
 | 
					  if (Bsec::spiObj) {
 | 
				
			||||||
 | 
					    Bsec::spiObj->beginTransaction(
 | 
				
			||||||
 | 
					        SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    digitalWrite(devId, LOW);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Bsec::spiObj->transfer(
 | 
				
			||||||
 | 
					        regAddr); // Write the register address, ignore the return
 | 
				
			||||||
 | 
					    for (uint16_t i = 0; i < length; i++)
 | 
				
			||||||
 | 
					      regData[i] = Bsec::spiObj->transfer(regData[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    digitalWrite(devId, HIGH);
 | 
				
			||||||
 | 
					    Bsec::spiObj->endTransaction();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    rslt = -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rslt;
 | 
				
			||||||
 | 
					  ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										230
									
								
								lib/Bosch-BSEC/src/bsec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								lib/Bosch-BSEC/src/bsec.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,230 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					 * modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistributions of source code must retain the above copyright
 | 
				
			||||||
 | 
					 * notice, this list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Redistributions in binary form must reproduce the above copyright
 | 
				
			||||||
 | 
					 * notice, this list of conditions and the following disclaimer in the
 | 
				
			||||||
 | 
					 * documentation and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Neither the name of the copyright holder nor the names of the
 | 
				
			||||||
 | 
					 * contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					 * this software without specific prior written permission.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
				
			||||||
 | 
					 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
				
			||||||
 | 
					 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					 * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
 | 
				
			||||||
 | 
					 * OR CONTRIBUTORS BE LIABLE FOR ANY
 | 
				
			||||||
 | 
					 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 | 
				
			||||||
 | 
					 * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
 | 
				
			||||||
 | 
					 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
				
			||||||
 | 
					 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
				
			||||||
 | 
					 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
				
			||||||
 | 
					 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
				
			||||||
 | 
					 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 | 
				
			||||||
 | 
					 * ANY WAY OUT OF THE USE OF THIS
 | 
				
			||||||
 | 
					 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The information provided is believed to be accurate and reliable.
 | 
				
			||||||
 | 
					 * The copyright holder 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 the copyright holder.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @file	bsec.h
 | 
				
			||||||
 | 
					 * @date	31 Jan 2018
 | 
				
			||||||
 | 
					 * @version	1.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef BSEC_CLASS_H
 | 
				
			||||||
 | 
					#define BSEC_CLASS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Includes */
 | 
				
			||||||
 | 
					#include "Arduino.h"
 | 
				
			||||||
 | 
					#include "Wire.h"
 | 
				
			||||||
 | 
					#include "SPI.h"
 | 
				
			||||||
 | 
					#include "inc/bsec_datatypes.h"
 | 
				
			||||||
 | 
					#include "inc/bsec_interface.h"
 | 
				
			||||||
 | 
					#include "bme680/bme680.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* BSEC class definition */
 | 
				
			||||||
 | 
					class Bsec
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						/* Public variables */
 | 
				
			||||||
 | 
						bsec_version_t version;		// Stores the version of the BSEC algorithm
 | 
				
			||||||
 | 
						int64_t nextCall;			// Stores the time when the algorithm has to be called next in ms
 | 
				
			||||||
 | 
						int8_t bme680Status;		// Placeholder for the BME680 driver's error codes
 | 
				
			||||||
 | 
						bsec_library_return_t status;
 | 
				
			||||||
 | 
						float iaqEstimate, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity,
 | 
				
			||||||
 | 
						      staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage;
 | 
				
			||||||
 | 
						uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAcccuracy;
 | 
				
			||||||
 | 
						int64_t outputTimestamp;	// Timestamp in ms of the output
 | 
				
			||||||
 | 
						static TwoWire *wireObj;
 | 
				
			||||||
 | 
						static SPIClass *spiObj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Public APIs */
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Constructor
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						Bsec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
						 * @param devId		: Device identifier parameter for the read/write interface functions
 | 
				
			||||||
 | 
						 * @param intf		: Physical communication interface
 | 
				
			||||||
 | 
						 * @param read		: Pointer to the read function
 | 
				
			||||||
 | 
						 * @param write		: Pointer to the write function
 | 
				
			||||||
 | 
						 * @param idleTask	: Pointer to the idling task
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
						 * @param i2cAddr	: I2C address
 | 
				
			||||||
 | 
						 * @param i2c		: Pointer to the TwoWire object
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void begin(uint8_t i2cAddr, TwoWire &i2c);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to initialize the BSEC library and the BME680 sensor
 | 
				
			||||||
 | 
						 * @param chipSelect	: SPI chip select
 | 
				
			||||||
 | 
						 * @param spi			: Pointer to the SPIClass object
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void begin(uint8_t chipSelect, SPIClass &spi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function that sets the desired sensors and the sample rates
 | 
				
			||||||
 | 
						 * @param sensorList	: The list of output sensors
 | 
				
			||||||
 | 
						 * @param nSensors		: Number of outputs requested
 | 
				
			||||||
 | 
						 * @param sampleRate	: The sample rate of requested sensors
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Callback from the user to trigger reading of data from the BME680, process and store outputs
 | 
				
			||||||
 | 
						 * @return true if there are new outputs. false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool run(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to get the state of the algorithm to save to non-volatile memory
 | 
				
			||||||
 | 
						 * @param state			: Pointer to a memory location that contains the state
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void getState(uint8_t *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to set the state of the algorithm from non-volatile memory
 | 
				
			||||||
 | 
						 * @param state			: Pointer to a memory location that contains the state
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void setState(uint8_t *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to set the configuration of the algorithm from memory
 | 
				
			||||||
 | 
						 * @param state			: Pointer to a memory location that contains the configuration
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void setConfig(const uint8_t *config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to set the temperature offset
 | 
				
			||||||
 | 
						 * @param tempOffset	: Temperature offset in degree Celsius
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void setTemperatureOffset(float tempOffset)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							_tempOffset = tempOffset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to calculate an int64_t timestamp in milliseconds
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int64_t getTimeMs(void);
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						* @brief Task that delays for a ms period of time
 | 
				
			||||||
 | 
						* @param period	: Period of time in ms
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						static void delay_ms(uint32_t period);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						* @brief Callback function for reading registers over I2C
 | 
				
			||||||
 | 
						* @param devId		: Library agnostic parameter to identify the device to communicate with
 | 
				
			||||||
 | 
						* @param regAddr	: Register address
 | 
				
			||||||
 | 
						* @param regData	: Pointer to the array containing the data to be read
 | 
				
			||||||
 | 
						* @param length	: Length of the array of data
 | 
				
			||||||
 | 
						* @return	Zero for success, non-zero otherwise
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						static int8_t i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						* @brief Callback function for writing registers over I2C
 | 
				
			||||||
 | 
						* @param devId		: Library agnostic parameter to identify the device to communicate with
 | 
				
			||||||
 | 
						* @param regAddr	: Register address
 | 
				
			||||||
 | 
						* @param regData	: Pointer to the array containing the data to be written
 | 
				
			||||||
 | 
						* @param length	: Length of the array of data
 | 
				
			||||||
 | 
						* @return	Zero for success, non-zero otherwise
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						static int8_t i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						* @brief Callback function for reading and writing registers over SPI
 | 
				
			||||||
 | 
						* @param devId		: Library agnostic parameter to identify the device to communicate with
 | 
				
			||||||
 | 
						* @param regAddr	: Register address
 | 
				
			||||||
 | 
						* @param regData	: Pointer to the array containing the data to be read or written
 | 
				
			||||||
 | 
						* @param length	: Length of the array of data
 | 
				
			||||||
 | 
						* @return	Zero for success, non-zero otherwise
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						static int8_t spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						/* Private variables */
 | 
				
			||||||
 | 
						struct bme680_dev _bme680;
 | 
				
			||||||
 | 
						struct bme680_field_data _data;
 | 
				
			||||||
 | 
						float _tempOffset;
 | 
				
			||||||
 | 
						// Global variables to help create a millisecond timestamp that doesn't overflow every 51 days.
 | 
				
			||||||
 | 
						// If it overflows, it will have a negative value. Something that should never happen.
 | 
				
			||||||
 | 
						uint32_t millisOverflowCounter;
 | 
				
			||||||
 | 
						uint32_t lastTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Private APIs */
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Get the version of the BSEC library
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void getVersion(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Read data from the BME680 and process it
 | 
				
			||||||
 | 
						 * @param currTimeNs: Current time in ns
 | 
				
			||||||
 | 
						 * @param bme680Settings: BME680 sensor's settings
 | 
				
			||||||
 | 
						 * @return true if there are new outputs. false otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Set the BME680 sensor's configuration
 | 
				
			||||||
 | 
						 * @param bme680Settings: Settings to configure the BME680
 | 
				
			||||||
 | 
						 * @return BME680 return code. BME680_OK for success, failure otherwise
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int8_t setBme680Config(bsec_bme_settings_t bme680Settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Common code for the begin function
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void beginCommon(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @brief Function to zero the outputs
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void zeroOutputs(void);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -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
 | 
				
			||||||
@ -16,7 +16,7 @@ env_default = generic
 | 
				
			|||||||
;env_default = ttgov21old
 | 
					;env_default = ttgov21old
 | 
				
			||||||
;env_default = ttgov21new
 | 
					;env_default = ttgov21new
 | 
				
			||||||
;env_default = ttgobeam_old
 | 
					;env_default = ttgobeam_old
 | 
				
			||||||
;env_default = ttgobeam_new
 | 
					env_default = ttgobeam_new
 | 
				
			||||||
;env_default = lopy
 | 
					;env_default = lopy
 | 
				
			||||||
;env_default = lopy4
 | 
					;env_default = lopy4
 | 
				
			||||||
;env_default = fipy
 | 
					;env_default = fipy
 | 
				
			||||||
@ -30,10 +30,10 @@ 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.7.01
 | 
					release_version = 1.7.03
 | 
				
			||||||
; 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 = 3
 | 
				
			||||||
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
 | 
					; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
 | 
				
			||||||
upload_protocol = esptool
 | 
					upload_protocol = esptool
 | 
				
			||||||
;upload_protocol = custom
 | 
					;upload_protocol = custom
 | 
				
			||||||
@ -70,8 +70,8 @@ build_flags_basic =
 | 
				
			|||||||
    '-DBINTRAY_PACKAGE="${PIOENV}"'
 | 
					    '-DBINTRAY_PACKAGE="${PIOENV}"'
 | 
				
			||||||
    '-DPROGVERSION="${common.release_version}"'
 | 
					    '-DPROGVERSION="${common.release_version}"'
 | 
				
			||||||
build_flags_sensors =
 | 
					build_flags_sensors =
 | 
				
			||||||
    -Llib/Bosch-BSEC
 | 
					    -Llib/Bosch-BSEC/src/esp32/
 | 
				
			||||||
    -llibalgobsec.a
 | 
					    -lalgobsec
 | 
				
			||||||
build_flags_all =
 | 
					build_flags_all =
 | 
				
			||||||
    ${common.build_flags_basic}
 | 
					    ${common.build_flags_basic}
 | 
				
			||||||
    ${common.build_flags_sensors}
 | 
					    ${common.build_flags_sensors}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,82 +8,85 @@ static const char TAG[] = "main";
 | 
				
			|||||||
bmeStatus_t bme_status;
 | 
					bmeStatus_t bme_status;
 | 
				
			||||||
TaskHandle_t BmeTask;
 | 
					TaskHandle_t BmeTask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float bme_offset = (float)BME_TEMP_OFFSET;
 | 
					Bsec iaqSensor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --- Bosch BSEC library configuration ---
 | 
					bsec_virtual_sensor_t sensorList[10] = {
 | 
				
			||||||
// 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
 | 
					    BSEC_OUTPUT_RAW_TEMPERATURE,
 | 
				
			||||||
// calibration. Change this const if not applicable for your application (see
 | 
					    BSEC_OUTPUT_RAW_PRESSURE,
 | 
				
			||||||
// BME680 datasheet)
 | 
					    BSEC_OUTPUT_RAW_HUMIDITY,
 | 
				
			||||||
const uint8_t bsec_config_iaq[454] = {
 | 
					    BSEC_OUTPUT_RAW_GAS,
 | 
				
			||||||
    1,   7,   4,   1,   61,  0,   0,   0,   0,   0,   0,   0,   174, 1,   0,
 | 
					    BSEC_OUTPUT_IAQ,
 | 
				
			||||||
    0,   48,  0,   1,   0,   137, 65,  0,   63,  205, 204, 204, 62,  0,   0,
 | 
					    BSEC_OUTPUT_STATIC_IAQ,
 | 
				
			||||||
    64,  63,  205, 204, 204, 62,  0,   0,   225, 68,  0,   192, 168, 71,  64,
 | 
					    BSEC_OUTPUT_CO2_EQUIVALENT,
 | 
				
			||||||
    49,  119, 76,  0,   0,   0,   0,   0,   80,  5,   95,  0,   0,   0,   0,
 | 
					    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
 | 
				
			||||||
    0,   0,   0,   0,   28,  0,   2,   0,   0,   244, 1,   225, 0,   25,  0,
 | 
					    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
 | 
				
			||||||
    0,   128, 64,  0,   0,   32,  65,  144, 1,   0,   0,   112, 65,  0,   0,
 | 
					    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
 | 
				
			||||||
    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) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // struct bme680_dev gas_sensor;
 | 
					  // block i2c bus access
 | 
				
			||||||
  Wire.begin(HAS_BME, 400000); // I2C connect to BME680 sensor with 400 KHz
 | 
					  if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
 | 
				
			||||||
 | 
					      pdTRUE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Call to the function which initializes the BSEC library
 | 
					    Wire.begin(HAS_BME);
 | 
				
			||||||
  // Switch on low-power mode and provide no temperature offset
 | 
					    iaqSensor.begin(BME_ADDR, Wire);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return_values_init ret =
 | 
					    ESP_LOGI(TAG, "BSEC v%d.%d.%d.%d", iaqSensor.version.major,
 | 
				
			||||||
      bsec_iot_init(BSEC_SAMPLE_RATE_LP, bme_offset, i2c_write, i2c_read,
 | 
					             iaqSensor.version.minor, iaqSensor.version.major_bugfix,
 | 
				
			||||||
                    user_delay_ms, state_load, config_load);
 | 
					             iaqSensor.version.minor_bugfix);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iaqSensor.setConfig(bsec_config_iaq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (checkIaqSensorStatus())
 | 
				
			||||||
 | 
					      ESP_LOGI(TAG, "BME680 sensor found and initialized");
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      ESP_LOGE(TAG, "BME680 sensor not found");
 | 
				
			||||||
 | 
					      return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iaqSensor.setTemperatureOffset((float)BME_TEMP_OFFSET);
 | 
				
			||||||
 | 
					    iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (checkIaqSensorStatus())
 | 
				
			||||||
 | 
					      ESP_LOGI(TAG, "BSEC subscription succesful");
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					      ESP_LOGE(TAG, "BSEC subscription error");
 | 
				
			||||||
 | 
					      return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xSemaphoreGive(I2Caccess); // release i2c bus access
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((int)ret.bme680_status) {
 | 
					 | 
				
			||||||
    ESP_LOGE(TAG, "Could not initialize BME680, error %d",
 | 
					 | 
				
			||||||
             (int)ret.bme680_status);
 | 
					 | 
				
			||||||
  } else if ((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_LOGE(TAG, "I2c bus busy - BME680 initialization error");
 | 
				
			||||||
    return 1;
 | 
					    return 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy,
 | 
					} // bme_init()
 | 
				
			||||||
                  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) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bme_status.temperature = temperature;
 | 
					// Helper function definitions
 | 
				
			||||||
  bme_status.humidity = humidity;
 | 
					int checkIaqSensorStatus(void) {
 | 
				
			||||||
  bme_status.pressure = (pressure / 100.0); // conversion Pa -> hPa
 | 
					  int rslt = 1; // true = 1 = no error, false = 0 = error
 | 
				
			||||||
  bme_status.iaq = iaq;
 | 
					
 | 
				
			||||||
}
 | 
					  if (iaqSensor.status != BSEC_OK) {
 | 
				
			||||||
 | 
					    rslt = 0;
 | 
				
			||||||
 | 
					    if (iaqSensor.status < BSEC_OK)
 | 
				
			||||||
 | 
					      ESP_LOGE(TAG, "BSEC error %d", iaqSensor.status);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "BSEC warning %d", iaqSensor.status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (iaqSensor.bme680Status != BME680_OK) {
 | 
				
			||||||
 | 
					    rslt = 0;
 | 
				
			||||||
 | 
					    if (iaqSensor.bme680Status < BME680_OK)
 | 
				
			||||||
 | 
					      ESP_LOGE(TAG, "BME680 error %d", iaqSensor.bme680Status);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "BME680 warning %d", iaqSensor.bme680Status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return rslt;
 | 
				
			||||||
 | 
					} // checkIaqSensorStatus()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// loop function which reads and processes data based on sensor settings
 | 
					// loop function which reads and processes data based on sensor settings
 | 
				
			||||||
void bme_loop(void *pvParameters) {
 | 
					void bme_loop(void *pvParameters) {
 | 
				
			||||||
@ -91,84 +94,31 @@ void bme_loop(void *pvParameters) {
 | 
				
			|||||||
  configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
 | 
					  configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAS_BME
 | 
					#ifdef HAS_BME
 | 
				
			||||||
  // State is saved every 10.000 samples, which means every 10.000 * 3 secs =
 | 
					  while (checkIaqSensorStatus()) {
 | 
				
			||||||
  // 500 minutes
 | 
					
 | 
				
			||||||
  bsec_iot_loop(user_delay_ms, get_timestamp_us, output_ready, state_save,
 | 
					    // block i2c bus access
 | 
				
			||||||
                10000);
 | 
					    if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
 | 
				
			||||||
 | 
					        pdTRUE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (iaqSensor.run()) { // If new data is available
 | 
				
			||||||
 | 
					        bme_status.raw_temperature = iaqSensor.rawTemperature;
 | 
				
			||||||
 | 
					        bme_status.raw_humidity = iaqSensor.rawHumidity;
 | 
				
			||||||
 | 
					        bme_status.temperature = iaqSensor.temperature;
 | 
				
			||||||
 | 
					        bme_status.humidity = iaqSensor.humidity;
 | 
				
			||||||
 | 
					        bme_status.pressure =
 | 
				
			||||||
 | 
					            (iaqSensor.pressure / 100.0); // conversion Pa -> hPa
 | 
				
			||||||
 | 
					        bme_status.iaq = iaqSensor.iaqEstimate;
 | 
				
			||||||
 | 
					        bme_status.iaq_accuracy = iaqSensor.iaqAccuracy;
 | 
				
			||||||
 | 
					        bme_status.gas = iaqSensor.gasResistance;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      xSemaphoreGive(I2Caccess); // release i2c bus access
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					  ESP_LOGE(TAG, "BME task ended");
 | 
				
			||||||
  vTaskDelete(BmeTask); // should never be reached
 | 
					  vTaskDelete(BmeTask); // should never be reached
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // bme_loop()
 | 
					} // bme_loop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
 | 
					 | 
				
			||||||
                uint16_t len) {
 | 
					 | 
				
			||||||
  int8_t rslt = 0;
 | 
					 | 
				
			||||||
  Wire.beginTransmission(dev_id);
 | 
					 | 
				
			||||||
  Wire.write(reg_addr);
 | 
					 | 
				
			||||||
  rslt = Wire.endTransmission(false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Wire.requestFrom((int)dev_id, (int)len);
 | 
					 | 
				
			||||||
  for (uint16_t i = 0; (i < len) && Wire.available(); i++) {
 | 
					 | 
				
			||||||
    reg_data[i] = Wire.read();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // return 0 for success, non-zero for failure
 | 
					 | 
				
			||||||
  return rslt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data,
 | 
					 | 
				
			||||||
                 uint16_t len) {
 | 
					 | 
				
			||||||
  Wire.beginTransmission(dev_id);
 | 
					 | 
				
			||||||
  Wire.write(reg_addr);
 | 
					 | 
				
			||||||
  for (uint16_t i = 0; i < len; i++) {
 | 
					 | 
				
			||||||
    Wire.write(reg_data[i]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  // return 0 for success, non-zero for failure
 | 
					 | 
				
			||||||
  return Wire.endTransmission(true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*!
 | 
					 | 
				
			||||||
 * @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.
 | 
					 | 
				
			||||||
  // ...
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void user_delay_ms(uint32_t period) { delay(period); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int64_t get_timestamp_us() { return (int64_t)millis() * 1000; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // HAS_BME
 | 
					#endif // HAS_BME
 | 
				
			||||||
@ -52,7 +52,12 @@ void doHousekeeping() {
 | 
				
			|||||||
// read battery voltage into global variable
 | 
					// read battery voltage into global variable
 | 
				
			||||||
#ifdef HAS_BATTERY_PROBE
 | 
					#ifdef HAS_BATTERY_PROBE
 | 
				
			||||||
  batt_voltage = read_voltage();
 | 
					  batt_voltage = read_voltage();
 | 
				
			||||||
  ESP_LOGI(TAG, "Measured Voltage: %dmV", batt_voltage);
 | 
					  ESP_LOGI(TAG, "Voltage: %dmV", batt_voltage);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// display BME sensor data if present
 | 
				
			||||||
 | 
					#ifdef HAS_BME
 | 
				
			||||||
 | 
					  ESP_LOGI(TAG, "BME680 Temp: %.2f°C | IAQ: %.2f", bme_status.temperature, bme_status.iaq);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // check free heap memory
 | 
					  // check free heap memory
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										136
									
								
								src/display.cpp
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/display.cpp
									
									
									
									
									
								
							@ -98,96 +98,104 @@ void init_display(const char *Productname, const char *Version) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void refreshtheDisplay() {
 | 
					void refreshtheDisplay() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // set display on/off according to current device configuration
 | 
					  // block i2c bus access
 | 
				
			||||||
  if (DisplayState != cfg.screenon) {
 | 
					  if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
 | 
				
			||||||
    DisplayState = cfg.screenon;
 | 
					      pdTRUE) {
 | 
				
			||||||
    u8x8.setPowerSave(!cfg.screenon);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // if display is switched off we don't refresh it and save time
 | 
					    // set display on/off according to current device configuration
 | 
				
			||||||
  if (!DisplayState)
 | 
					    if (DisplayState != cfg.screenon) {
 | 
				
			||||||
    return;
 | 
					      DisplayState = cfg.screenon;
 | 
				
			||||||
 | 
					      u8x8.setPowerSave(!cfg.screenon);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint8_t msgWaiting;
 | 
					    // if display is switched off we don't refresh it and save time
 | 
				
			||||||
  char buff[16]; // 16 chars line buffer
 | 
					    if (!DisplayState)
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // update counter (lines 0-1)
 | 
					    uint8_t msgWaiting;
 | 
				
			||||||
  snprintf(
 | 
					    char buff[16]; // 16 chars line buffer
 | 
				
			||||||
      buff, sizeof(buff), "PAX:%-4d",
 | 
					
 | 
				
			||||||
      (int)macs.size()); // convert 16-bit MAC counter to decimal counter value
 | 
					    // update counter (lines 0-1)
 | 
				
			||||||
  u8x8.draw2x2String(0, 0,
 | 
					    snprintf(
 | 
				
			||||||
                     buff); // display number on unique macs total Wifi + BLE
 | 
					        buff, sizeof(buff), "PAX:%-4d",
 | 
				
			||||||
 | 
					        (int)
 | 
				
			||||||
 | 
					            macs.size()); // convert 16-bit MAC counter to decimal counter value
 | 
				
			||||||
 | 
					    u8x8.draw2x2String(0, 0,
 | 
				
			||||||
 | 
					                       buff); // display number on unique macs total Wifi + BLE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// update Battery status (line 2)
 | 
					// update Battery status (line 2)
 | 
				
			||||||
#ifdef HAS_BATTERY_PROBE
 | 
					#ifdef HAS_BATTERY_PROBE
 | 
				
			||||||
  u8x8.setCursor(0, 2);
 | 
					    u8x8.setCursor(0, 2);
 | 
				
			||||||
  u8x8.printf("B:%.1fV", batt_voltage / 1000.0);
 | 
					    u8x8.printf("B:%.1fV", batt_voltage / 1000.0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// update GPS status (line 2)
 | 
					// update GPS status (line 2)
 | 
				
			||||||
#ifdef HAS_GPS
 | 
					#ifdef HAS_GPS
 | 
				
			||||||
  u8x8.setCursor(9, 2);
 | 
					    u8x8.setCursor(9, 2);
 | 
				
			||||||
  if (!gps.location.isValid()) // if no fix then display Sats value inverse
 | 
					    if (!gps.location.isValid()) // if no fix then display Sats value inverse
 | 
				
			||||||
  {
 | 
					    {
 | 
				
			||||||
    u8x8.setInverseFont(1);
 | 
					      u8x8.setInverseFont(1);
 | 
				
			||||||
    u8x8.printf("Sats:%.2d", gps.satellites.value());
 | 
					      u8x8.printf("Sats:%.2d", gps.satellites.value());
 | 
				
			||||||
    u8x8.setInverseFont(0);
 | 
					      u8x8.setInverseFont(0);
 | 
				
			||||||
  } else
 | 
					    } else
 | 
				
			||||||
    u8x8.printf("Sats:%.2d", gps.satellites.value());
 | 
					      u8x8.printf("Sats:%.2d", gps.satellites.value());
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // update bluetooth counter + LoRa SF (line 3)
 | 
					      // update bluetooth counter + LoRa SF (line 3)
 | 
				
			||||||
#ifdef BLECOUNTER
 | 
					#ifdef BLECOUNTER
 | 
				
			||||||
  u8x8.setCursor(0, 3);
 | 
					    u8x8.setCursor(0, 3);
 | 
				
			||||||
  if (cfg.blescan)
 | 
					    if (cfg.blescan)
 | 
				
			||||||
    u8x8.printf("BLTH:%-4d", macs_ble);
 | 
					      u8x8.printf("BLTH:%-4d", macs_ble);
 | 
				
			||||||
  else
 | 
					    else
 | 
				
			||||||
    u8x8.printf("%s", "BLTH:off");
 | 
					      u8x8.printf("%s", "BLTH:off");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAS_LORA
 | 
					#ifdef HAS_LORA
 | 
				
			||||||
  u8x8.setCursor(11, 3);
 | 
					    u8x8.setCursor(11, 3);
 | 
				
			||||||
  u8x8.printf("SF:");
 | 
					    u8x8.printf("SF:");
 | 
				
			||||||
  if (cfg.adrmode) // if ADR=on then display SF value inverse
 | 
					    if (cfg.adrmode) // if ADR=on then display SF value inverse
 | 
				
			||||||
    u8x8.setInverseFont(1);
 | 
					      u8x8.setInverseFont(1);
 | 
				
			||||||
  u8x8.printf("%c%c", lora_datarate[LMIC.datarate * 2],
 | 
					    u8x8.printf("%c%c", lora_datarate[LMIC.datarate * 2],
 | 
				
			||||||
              lora_datarate[LMIC.datarate * 2 + 1]);
 | 
					                lora_datarate[LMIC.datarate * 2 + 1]);
 | 
				
			||||||
  if (cfg.adrmode) // switch off inverse if it was turned on
 | 
					    if (cfg.adrmode) // switch off inverse if it was turned on
 | 
				
			||||||
    u8x8.setInverseFont(0);
 | 
					      u8x8.setInverseFont(0);
 | 
				
			||||||
#endif // HAS_LORA
 | 
					#endif // HAS_LORA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // update wifi counter + channel display (line 4)
 | 
					    // update wifi counter + channel display (line 4)
 | 
				
			||||||
  u8x8.setCursor(0, 4);
 | 
					    u8x8.setCursor(0, 4);
 | 
				
			||||||
  u8x8.printf("WIFI:%-4d", macs_wifi);
 | 
					    u8x8.printf("WIFI:%-4d", macs_wifi);
 | 
				
			||||||
  u8x8.setCursor(11, 4);
 | 
					    u8x8.setCursor(11, 4);
 | 
				
			||||||
  u8x8.printf("ch:%02d", channel);
 | 
					    u8x8.printf("ch:%02d", channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // update RSSI limiter status & free memory display (line 5)
 | 
					    // update RSSI limiter status & free memory display (line 5)
 | 
				
			||||||
  u8x8.setCursor(0, 5);
 | 
					    u8x8.setCursor(0, 5);
 | 
				
			||||||
  u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit);
 | 
					    u8x8.printf(!cfg.rssilimit ? "RLIM:off " : "RLIM:%-4d", cfg.rssilimit);
 | 
				
			||||||
  u8x8.setCursor(10, 5);
 | 
					    u8x8.setCursor(10, 5);
 | 
				
			||||||
  u8x8.printf("%4dKB", getFreeRAM() / 1024);
 | 
					    u8x8.printf("%4dKB", getFreeRAM() / 1024);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAS_LORA
 | 
					#ifdef HAS_LORA
 | 
				
			||||||
  // update LoRa status display (line 6)
 | 
					    // update LoRa status display (line 6)
 | 
				
			||||||
  u8x8.setCursor(0, 6);
 | 
					    u8x8.setCursor(0, 6);
 | 
				
			||||||
  u8x8.printf("%-16s", display_line6);
 | 
					    u8x8.printf("%-16s", display_line6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // update LMiC event display (line 7)
 | 
					    // update LMiC event display (line 7)
 | 
				
			||||||
  u8x8.setCursor(0, 7);
 | 
					    u8x8.setCursor(0, 7);
 | 
				
			||||||
  u8x8.printf("%-14s", display_line7);
 | 
					    u8x8.printf("%-14s", display_line7);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // update LoRa send queue display (line 7)
 | 
					    // update LoRa send queue display (line 7)
 | 
				
			||||||
  msgWaiting = uxQueueMessagesWaiting(LoraSendQueue);
 | 
					    msgWaiting = uxQueueMessagesWaiting(LoraSendQueue);
 | 
				
			||||||
  if (msgWaiting) {
 | 
					    if (msgWaiting) {
 | 
				
			||||||
    sprintf(buff, "%2d", msgWaiting);
 | 
					      sprintf(buff, "%2d", msgWaiting);
 | 
				
			||||||
    u8x8.setCursor(14, 7);
 | 
					      u8x8.setCursor(14, 7);
 | 
				
			||||||
    u8x8.printf("%-2s", msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff);
 | 
					      u8x8.printf("%-2s", msgWaiting == SEND_QUEUE_SIZE ? "<>" : buff);
 | 
				
			||||||
  } else
 | 
					    } else
 | 
				
			||||||
    u8x8.printf("  ");
 | 
					      u8x8.printf("  ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // HAS_LORA
 | 
					#endif // HAS_LORA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xSemaphoreGive(I2Caccess); // release i2c bus access
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // refreshDisplay()
 | 
					} // refreshDisplay()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // HAS_DISPLAY
 | 
					#endif // HAS_DISPLAY
 | 
				
			||||||
@ -17,8 +17,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// enable only if device has these sensors, otherwise comment these lines
 | 
					// enable only if device has these sensors, otherwise comment these lines
 | 
				
			||||||
// BME680 sensor on I2C bus
 | 
					// BME680 sensor on I2C bus
 | 
				
			||||||
// don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
 | 
					 | 
				
			||||||
#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | 
					#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | 
				
			||||||
 | 
					#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// user defined sensors
 | 
					// user defined sensors
 | 
				
			||||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
					//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
				
			||||||
 | 
				
			|||||||
@ -11,11 +11,9 @@
 | 
				
			|||||||
// disable brownout detection (avoid unexpected reset on some boards)
 | 
					// disable brownout detection (avoid unexpected reset on some boards)
 | 
				
			||||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
 | 
					#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// enable only if device has these sensors, otherwise comment these lines
 | 
					 | 
				
			||||||
// BME680 sensor on I2C bus
 | 
					 | 
				
			||||||
// Octopus32 has a pre-populated BME680 on i2c addr 0x76
 | 
					// Octopus32 has a pre-populated BME680 on i2c addr 0x76
 | 
				
			||||||
#define HAS_BME GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
 | 
					#define HAS_BME GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
 | 
				
			||||||
//#define HAS_BME 0x76
 | 
					#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// user defined sensors
 | 
					// user defined sensors
 | 
				
			||||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
					//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
				
			||||||
 | 
				
			|||||||
@ -8,22 +8,21 @@
 | 
				
			|||||||
// Hardware related definitions for TTGO T-Beam board
 | 
					// Hardware related definitions for TTGO T-Beam board
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
 | 
					// pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
 | 
				
			||||||
//
 | 
					
 | 
				
			||||||
// enable only if device has these sensors, otherwise comment these lines
 | 
					// enable only if device has these sensors, otherwise comment these lines
 | 
				
			||||||
// BME680 sensor on I2C bus
 | 
					// BME680 sensor on I2C bus
 | 
				
			||||||
// don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
 | 
					#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | 
				
			||||||
//
 | 
					#define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | 
				
			||||||
//#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HAS_LED GPIO_NUM_14 // on board green LED
 | 
					#define HAS_LED GPIO_NUM_14 // on board green LED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// user defined sensors
 | 
					// user defined sensors
 | 
				
			||||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
					//#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
 | 
					#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
 | 
				
			||||||
//#define MY_OLED_SDA (21)
 | 
					#define MY_OLED_SDA (21)
 | 
				
			||||||
//#define MY_OLED_SCL (22)
 | 
					#define MY_OLED_SCL (22)
 | 
				
			||||||
//#define MY_OLED_RST (NOT_A_PIN)
 | 
					#define MY_OLED_RST U8X8_PIN_NONE
 | 
				
			||||||
//#define DISPLAY_FLIP  1 // use if display is rotated
 | 
					//#define DISPLAY_FLIP  1 // use if display is rotated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HAS_LORA 1       // comment out if device shall not send data via LoRa
 | 
					#define HAS_LORA 1       // comment out if device shall not send data via LoRa
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@
 | 
				
			|||||||
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
 | 
					//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
 | 
				
			||||||
//#define MY_OLED_SDA (21)
 | 
					//#define MY_OLED_SDA (21)
 | 
				
			||||||
//#define MY_OLED_SCL (22)
 | 
					//#define MY_OLED_SCL (22)
 | 
				
			||||||
//#define MY_OLED_RST (NOT_A_PIN)
 | 
					//#define MY_OLED_RST U8X8_PIN_NONE
 | 
				
			||||||
//#define DISPLAY_FLIP  1 // use if display is rotated
 | 
					//#define DISPLAY_FLIP  1 // use if display is rotated
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HAS_LORA 1       // comment out if device shall not send data via LoRa
 | 
					#define HAS_LORA 1       // comment out if device shall not send data via LoRa
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/main.cpp
									
									
									
									
									
								
							@ -35,11 +35,14 @@ IDLE          0     0     ESP32 arduino scheduler -> runs wifi sniffer
 | 
				
			|||||||
looptask      1     1     arduino core -> runs the LMIC LoRa stack
 | 
					looptask      1     1     arduino core -> runs the LMIC LoRa stack
 | 
				
			||||||
irqhandler    1     1     executes tasks triggered by irq
 | 
					irqhandler    1     1     executes tasks triggered by irq
 | 
				
			||||||
gpsloop       1     2     reads data from GPS via serial or i2c
 | 
					gpsloop       1     2     reads data from GPS via serial or i2c
 | 
				
			||||||
bmeloop       1     0     reads data from BME sensor via i2c
 | 
					bmeloop       1     1     reads data from BME sensor via i2c
 | 
				
			||||||
IDLE          1     0     ESP32 arduino scheduler
 | 
					IDLE          1     0     ESP32 arduino scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Low priority numbers denote low priority tasks.
 | 
					Low priority numbers denote low priority tasks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tasks using i2c bus all must have same priority, because using mutex semaphore
 | 
				
			||||||
 | 
					(irqhandler, bmeloop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ESP32 hardware timers
 | 
					ESP32 hardware timers
 | 
				
			||||||
==========================
 | 
					==========================
 | 
				
			||||||
 0	Trigger display refresh
 | 
					 0	Trigger display refresh
 | 
				
			||||||
@ -60,6 +63,7 @@ uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
 | 
				
			|||||||
hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL,
 | 
					hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL,
 | 
				
			||||||
           *displaytimer = NULL; // irq tasks
 | 
					           *displaytimer = NULL; // irq tasks
 | 
				
			||||||
TaskHandle_t irqHandlerTask, wifiSwitchTask;
 | 
					TaskHandle_t irqHandlerTask, wifiSwitchTask;
 | 
				
			||||||
 | 
					SemaphoreHandle_t I2Caccess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
 | 
					// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
 | 
				
			||||||
// if present
 | 
					// if present
 | 
				
			||||||
@ -78,6 +82,14 @@ void setup() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  char features[100] = "";
 | 
					  char features[100] = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (I2Caccess == NULL) // Check that semaphore has not already been created
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    I2Caccess = xSemaphoreCreateMutex(); // Create a mutex semaphore we will use
 | 
				
			||||||
 | 
					                                         // to manage the i2c bus
 | 
				
			||||||
 | 
					    if ((I2Caccess) != NULL)
 | 
				
			||||||
 | 
					      xSemaphoreGive((I2Caccess)); // Flag the i2c bus available for use
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // disable brownout detection
 | 
					  // disable brownout detection
 | 
				
			||||||
#ifdef DISABLE_BROWNOUT
 | 
					#ifdef DISABLE_BROWNOUT
 | 
				
			||||||
  // register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
 | 
					  // register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
 | 
				
			||||||
@ -343,11 +355,11 @@ void setup() {
 | 
				
			|||||||
                            "bmeloop", // name of task
 | 
					                            "bmeloop", // name of task
 | 
				
			||||||
                            4096,      // stack size of task
 | 
					                            4096,      // stack size of task
 | 
				
			||||||
                            (void *)1, // parameter of the task
 | 
					                            (void *)1, // parameter of the task
 | 
				
			||||||
                            0,         // priority of the task
 | 
					                            //0,         // priority of the task
 | 
				
			||||||
 | 
					                            1,         // priority of the task
 | 
				
			||||||
                            &BmeTask,  // task handle
 | 
					                            &BmeTask,  // task handle
 | 
				
			||||||
                            1);        // CPU core
 | 
					                            1);        // CPU core
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  delay(2000); // time for initializing i2c sensor
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // start timer triggered interrupts
 | 
					  // start timer triggered interrupts
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user