343 lines
13 KiB
Arduino
343 lines
13 KiB
Arduino
|
/*
|
||
|
* Copyright (C) 2017 Robert Bosch. All Rights Reserved.
|
||
|
*
|
||
|
* Disclaimer
|
||
|
*
|
||
|
* Common:
|
||
|
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
||
|
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
||
|
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
||
|
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
||
|
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
||
|
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
||
|
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
||
|
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
||
|
*
|
||
|
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
||
|
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
||
|
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
||
|
* Sensortec for all costs in connection with such claims.
|
||
|
*
|
||
|
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
||
|
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
||
|
*
|
||
|
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
||
|
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
||
|
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
||
|
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
||
|
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
||
|
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
||
|
* samples.
|
||
|
*
|
||
|
* Special:
|
||
|
* This software module (hereinafter called "Software") and any information on application-sheets
|
||
|
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
||
|
* application work. The Software and Information is subject to the following terms and conditions:
|
||
|
*
|
||
|
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
||
|
* personnel who have special experience and training. Do not use this Software if you do not have the
|
||
|
* proper experience or training.
|
||
|
*
|
||
|
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
||
|
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
||
|
* purpose.
|
||
|
*
|
||
|
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
||
|
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
||
|
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
||
|
* otherwise stipulated in mandatory applicable law.
|
||
|
*
|
||
|
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
||
|
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
||
|
* other rights of third parties which may result from its use. No license is granted by implication or
|
||
|
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
||
|
* subject to change without notice.
|
||
|
*
|
||
|
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
||
|
* Bosch Sensortec.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* @file bsec_iot_ulp_plus_example.ino
|
||
|
*
|
||
|
* @brief
|
||
|
* Example for using of BSEC library in a fixed configuration with the BME680 sensor.
|
||
|
* This works by running an endless loop in the bsec_iot_loop() function.
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* @addtogroup bsec_examples BSEC Examples
|
||
|
* @brief BSEC usage examples
|
||
|
* @{*/
|
||
|
|
||
|
/**********************************************************************************************************************/
|
||
|
/* header files */
|
||
|
/**********************************************************************************************************************/
|
||
|
|
||
|
#include "bsec_integration.h"
|
||
|
#include "bsec_serialized_configurations_iaq.h"
|
||
|
#include <Wire.h>
|
||
|
|
||
|
/**********************************************************************************************************************/
|
||
|
/* functions */
|
||
|
/**********************************************************************************************************************/
|
||
|
|
||
|
/*!
|
||
|
* @brief Write operation in either Wire or SPI
|
||
|
*
|
||
|
* param[in] dev_addr Wire or SPI device address
|
||
|
* param[in] reg_addr register address
|
||
|
* param[in] reg_data_ptr pointer to the data to be written
|
||
|
* param[in] data_len number of bytes to be written
|
||
|
*
|
||
|
* @return result of the bus communication function
|
||
|
*/
|
||
|
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
||
|
{
|
||
|
Wire.beginTransmission(dev_addr);
|
||
|
Wire.write(reg_addr); /* Set register address to start writing to */
|
||
|
|
||
|
/* Write the data */
|
||
|
for (int index = 0; index < data_len; index++) {
|
||
|
Wire.write(reg_data_ptr[index]);
|
||
|
}
|
||
|
|
||
|
return (int8_t)Wire.endTransmission();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Read operation in either Wire or SPI
|
||
|
*
|
||
|
* param[in] dev_addr Wire or SPI device address
|
||
|
* param[in] reg_addr register address
|
||
|
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
|
||
|
* param[in] data_len number of bytes to be read
|
||
|
*
|
||
|
* @return result of the bus communication function
|
||
|
*/
|
||
|
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
|
||
|
{
|
||
|
int8_t comResult = 0;
|
||
|
Wire.beginTransmission(dev_addr);
|
||
|
Wire.write(reg_addr); /* Set register address to start reading from */
|
||
|
comResult = Wire.endTransmission();
|
||
|
|
||
|
delayMicroseconds(150); /* Precautionary response delay */
|
||
|
Wire.requestFrom(dev_addr, (uint8_t)data_len); /* Request data */
|
||
|
|
||
|
int index = 0;
|
||
|
while (Wire.available()) /* The slave device may send less than requested (burst read) */
|
||
|
{
|
||
|
reg_data_ptr[index] = Wire.read();
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
return comResult;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief System specific implementation of sleep function
|
||
|
*
|
||
|
* @param[in] t_ms time in milliseconds
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void sleep(uint32_t t_ms)
|
||
|
{
|
||
|
delay(t_ms);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Capture the system time in microseconds
|
||
|
*
|
||
|
* @return system_current_time current system timestamp in microseconds
|
||
|
*/
|
||
|
int64_t get_timestamp_us()
|
||
|
{
|
||
|
return (int64_t) millis() * 1000;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Handling of the ready outputs
|
||
|
*
|
||
|
* @param[in] timestamp time in nanoseconds
|
||
|
* @param[in] iaq IAQ signal
|
||
|
* @param[in] iaq_accuracy accuracy of IAQ signal
|
||
|
* @param[in] temperature temperature signal
|
||
|
* @param[in] humidity humidity signal
|
||
|
* @param[in] pressure pressure signal
|
||
|
* @param[in] raw_temperature raw temperature signal
|
||
|
* @param[in] raw_humidity raw humidity signal
|
||
|
* @param[in] gas raw gas sensor signal
|
||
|
* @param[in] bsec_status value returned by the bsec_do_steps() call
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
|
||
|
float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
|
||
|
float static_iaq, float co2_equivalent, float breath_voc_equivalent)
|
||
|
{
|
||
|
Serial.print("[");
|
||
|
Serial.print(timestamp/1e6);
|
||
|
Serial.print("] T: ");
|
||
|
Serial.print(temperature);
|
||
|
Serial.print("| rH: ");
|
||
|
Serial.print(humidity);
|
||
|
Serial.print("| IAQ: ");
|
||
|
Serial.print(iaq);
|
||
|
Serial.print(" (");
|
||
|
Serial.print(iaq_accuracy);
|
||
|
Serial.println(")");
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Load previous library state from non-volatile memory
|
||
|
*
|
||
|
* @param[in,out] state_buffer buffer to hold the loaded state string
|
||
|
* @param[in] n_buffer size of the allocated state buffer
|
||
|
*
|
||
|
* @return number of bytes copied to state_buffer
|
||
|
*/
|
||
|
uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
|
||
|
{
|
||
|
// ...
|
||
|
// Load a previous library state from non-volatile memory, if available.
|
||
|
//
|
||
|
// Return zero if loading was unsuccessful or no state was available,
|
||
|
// otherwise return length of loaded state string.
|
||
|
// ...
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Save library state to non-volatile memory
|
||
|
*
|
||
|
* @param[in] state_buffer buffer holding the state to be stored
|
||
|
* @param[in] length length of the state string to be stored
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void state_save(const uint8_t *state_buffer, uint32_t length)
|
||
|
{
|
||
|
// ...
|
||
|
// Save the string some form of non-volatile memory, if possible.
|
||
|
// ...
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Load library config from non-volatile memory
|
||
|
*
|
||
|
* @param[in,out] config_buffer buffer to hold the loaded state string
|
||
|
* @param[in] n_buffer size of the allocated state buffer
|
||
|
*
|
||
|
* @return number of bytes copied to config_buffer
|
||
|
*/
|
||
|
uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
|
||
|
{
|
||
|
// ...
|
||
|
// Load a library config from non-volatile memory, if available.
|
||
|
//
|
||
|
// Return zero if loading was unsuccessful or no config was available,
|
||
|
// otherwise return length of loaded config string.
|
||
|
// ...
|
||
|
|
||
|
memcpy(config_buffer, bsec_config_iaq, sizeof(bsec_config_iaq));
|
||
|
return sizeof(bsec_config_iaq);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Interrupt handler for press of a ULP plus button
|
||
|
*
|
||
|
* @return none
|
||
|
*/
|
||
|
void ulp_plus_button_press()
|
||
|
{
|
||
|
/* We call bsec_update_subscription() in order to instruct BSEC to perform an extra measurement at the next
|
||
|
* possible time slot
|
||
|
*/
|
||
|
|
||
|
bsec_sensor_configuration_t requested_virtual_sensors[1];
|
||
|
uint8_t n_requested_virtual_sensors = 1;
|
||
|
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
|
||
|
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
|
||
|
bsec_library_return_t status = BSEC_OK;
|
||
|
|
||
|
/* To trigger a ULP plus, we request the IAQ virtual sensor with a specific sample rate code */
|
||
|
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ_ESTIMATE;
|
||
|
requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND;
|
||
|
|
||
|
/* Call bsec_update_subscription() to enable/disable the requested virtual sensors */
|
||
|
status = bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings,
|
||
|
&n_required_sensor_settings);
|
||
|
|
||
|
/* The status code would tell is if the request was accepted. It will be rejected if the sensor is not already in
|
||
|
* ULP mode, or if the time difference between requests is too short, for example. */
|
||
|
if (status == BSEC_OK)
|
||
|
{
|
||
|
Serial.println("ULP plus triggered sucessfully.");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Serial.print("ULP plus request rejected. ");
|
||
|
switch (status)
|
||
|
{
|
||
|
case BSEC_W_SC_MODEXCEEDULPTIMELIMIT:
|
||
|
Serial.println("Request came within 20 s of a previous measurement.");
|
||
|
break;
|
||
|
case BSEC_W_SC_MODINSUFFICIENTWAITTIME:
|
||
|
Serial.println("Request came within 20 s of a ULP plus.");
|
||
|
break;
|
||
|
case BSEC_W_SU_MODINNOULP:
|
||
|
Serial.println("Sensor not in ULP mode.");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* @brief Main function which configures BSEC library and then reads and processes the data from sensor based
|
||
|
* on timer ticks
|
||
|
*
|
||
|
* @return result of the processing
|
||
|
*/
|
||
|
void setup()
|
||
|
{
|
||
|
return_values_init ret;
|
||
|
|
||
|
/* Init I2C and serial communication */
|
||
|
Wire.begin();
|
||
|
Serial.begin(115200);
|
||
|
|
||
|
/* Setup button interrupt to trigger ULP plus */
|
||
|
pinMode(2, INPUT_PULLUP);
|
||
|
attachInterrupt(digitalPinToInterrupt(2), ulp_plus_button_press, FALLING);
|
||
|
|
||
|
/* Call to the function which initializes the BSEC library
|
||
|
* Switch on ultra_low-power mode and provide no temperature offset */
|
||
|
ret = bsec_iot_init(BSEC_SAMPLE_RATE_ULP, 5.0f, bus_write, bus_read, sleep, state_load, config_load);
|
||
|
if (ret.bme680_status)
|
||
|
{
|
||
|
/* Could not intialize BME680 */
|
||
|
Serial.println("Error while initializing BME680");
|
||
|
return;
|
||
|
}
|
||
|
else if (ret.bsec_status)
|
||
|
{
|
||
|
/* Could not intialize BSEC library */
|
||
|
Serial.println("Error while initializing BSEC library");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Call to endless loop function which reads and processes data based on sensor settings */
|
||
|
/* State is saved every 10.000 samples, which means every 100 * 300 secs = 500 minutes */
|
||
|
bsec_iot_loop(sleep, get_timestamp_us, output_ready, state_save, 100);
|
||
|
}
|
||
|
|
||
|
void loop()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/*! @}*/
|
||
|
|