first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
41
libraries/bsec2/LICENSE.md
Normal file
41
libraries/bsec2/LICENSE.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
## Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
|
||||
## BSEC v2.x Arduino Library
|
||||
|
||||
**Date** : 2021/07/14
|
||||
|
||||
**Usage** : Arduino Library and examples for the BSEC 2.x software library for the BME68x family of sensors
|
||||
|
||||
> The binaries redistributed as part of this repository are licensed under the [License Terms and Conditions for the use of Bosch Sensortec GmbH,
|
||||
Reutlingen, BME688 Software (esp. BME AI-Studio & BSEC 2.x)](https://www.bosch-sensortec.com/media/boschsensortec/downloads/software/bme688_development_software/2023_04/license_terms_bme688_bme680_bsec.pdf)
|
||||
|
||||
>The examples and Arduino library are licensed under the BSD-3-Clause license.
|
||||
>
|
||||
>BSD-3-Clause
|
||||
>
|
||||
>Redistribution and use in source and binary forms, with or without
|
||||
>modification, are permitted provided that the following conditions are >met:
|
||||
>
|
||||
>1. Redistributions of source code must retain the above copyright
|
||||
> notice, this list of conditions and the following disclaimer.
|
||||
>
|
||||
>2. Redistributions in binary form must reproduce the above copyright
|
||||
> notice, this list of conditions and the following disclaimer in the
|
||||
> documentation and/or other materials provided with the distribution.
|
||||
>
|
||||
>3. Neither the name of the copyright holder nor the names of its
|
||||
> contributors may be used to endorse or promote products derived from
|
||||
> this software without specific prior written permission.
|
||||
>
|
||||
>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
111
libraries/bsec2/README.md
Normal file
111
libraries/bsec2/README.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
# Instructions for using the BSEC Arduino Library in Arduino 1.8.19
|
||||
|
||||
## About BSEC
|
||||
|
||||
Bosch Sensortec Environmental Cluster (BSEC) Software v2.6.1.0 released on July, 29th 2024
|
||||
|
||||
The BSEC fusion library has been conceptualized to provide a higher-level signal processing and fusion for the BME688. The library receives compensated sensor values from the sensor API. It processes the BME688 signals to provide the requested sensor outputs.
|
||||
|
||||
Key features
|
||||
|
||||
- Selectivity to target gas classes
|
||||
- Calculation of index for air quality (IAQ) level outside of the device
|
||||
- Calculation of ambient air temperature outside of the device (e.g. phone)
|
||||
- Calculation of ambient relative humidity outside of the device
|
||||
|
||||
Typical applications
|
||||
|
||||
- Indoor air quality
|
||||
- Home automation and control
|
||||
- Internet of things
|
||||
- Weather forecast
|
||||
- GPS enhancement (e.g. time-to-first-fix improvement, dead reckoning, slope detection)
|
||||
- Indoor navigation (change of floor detection, elevator detection)
|
||||
- Outdoor navigation, leisure and sports applications
|
||||
- Vertical velocity indication (rise/sink speed)
|
||||
|
||||
Supported platforms
|
||||
|
||||
- BSEC library is supported on 32, 16 and 8 bit MCU platforms
|
||||
|
||||
Available binaries for download:
|
||||
|
||||
| Platform | Compiler | TYPE |
|
||||
|----------|----------|------|
|
||||
| Cortex-ARM | GCC | Cortex-M0+, M3, M4, M4_FPU, M33, M33_FPU |
|
||||
| ESP8266 | xtensa-lx106-elf-gcc | ESP8266 |
|
||||
| ESP32 | xtensa-esp32-elf-gcc | ESP32 |
|
||||
| ESP32 | xtensa-esp32s2-elf-gcc | ESP32-S2 |
|
||||
| ESP32 | xtensa-esp32s3-elf-gcc | ESP32-S3 |
|
||||
| ESP32 | riscv32-esp-elf-gcc | ESP32-C3 |
|
||||
|
||||
Note: The following libraries are not tested - M4 and M33
|
||||
|
||||
The library size information above doesn't include additional dependencies based on the embedded system project & platform.
|
||||
|
||||
For other platforms, please contact your local Bosch Sensortec representative
|
||||
|
||||
Advantages
|
||||
|
||||
- Easy to integrate
|
||||
- Hardware and software co-design for optimal performance
|
||||
- Complete software fusion solution out of one hand
|
||||
- Eliminates need for own fusion software development
|
||||
- Robust virtual sensor outputs optimized for the application
|
||||
|
||||
## Software license agreement
|
||||
|
||||
The BSEC software is only available for download or use after accepting the software license agreement. By using this library, you have agreed to the terms of the license agreement.
|
||||
|
||||
[BSEC license agreement](https://www.bosch-sensortec.com/media/boschsensortec/downloads/software/bme688_development_software/2023_04/license_terms_bme688_bme680_bsec.pdf)
|
||||
|
||||
## Installation and getting started
|
||||
|
||||
### 1. Install the latest Arduino IDE
|
||||
|
||||
As of this publication, the latest Arduino IDE 1.8.19 can be downloaded from this [link](https://www.arduino.cc/en/software)
|
||||
|
||||
### 2. Install the BSEC2 library and BME68x Library
|
||||
|
||||
Download [Bosch_BSEC2_Library](https://github.com/BoschSensortec/Bosch-BSEC2-Library) and [Bosch_BME68x_Library](https://github.com/BoschSensortec/Bosch-BME68x-Library) (this library is a dependency to the BSEC2 library) as a zip and import it into the Arduino IDE. Refer to [this](https://www.arduino.cc/en/Guide/Libraries) guide on how to import libraries.
|
||||
|
||||
### 3. Install esp32 Board package in the Arduino IDE
|
||||
|
||||
- Open File->Preferences->Settings
|
||||
|
||||
- Insert the following link into the "Additional Boards Manager URLs":
|
||||
|
||||
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
||||
|
||||
**Note:** Please ensure that the proxy settings are updated under File->Preferences->Network
|
||||
|
||||
- Go to Tools->Board->Boards Manager and search for "esp32"
|
||||
|
||||
- Install the esp32 package
|
||||
|
||||
### 4. Verify and upload the example code
|
||||
|
||||
Start or restart the Arduino IDE. Open any of the example codes found under ```Bosch_BSEC2_Library>examples```.
|
||||
|
||||
Select your board and COM port. Upload the example. Open the Serial monitor. You should see an output on the terminal.
|
||||
|
||||
### More about example codes:
|
||||
|
||||
- basic.ino: This is an example for illustrating the basic BSEC virtual outputs.
|
||||
|
||||
- basic_config_state.ino: This is an example for illustrating the BSEC feature using desired configuration setting.
|
||||
|
||||
- bme68x_demo_sample.ino: This demonstrator application running on an x8 board has the feature of sensor data logging and BSEC algorithm illustration. Please refer [BME688 Development Kit-Firmware-Quick-Start-Guide](examples/bme68x_demo_sample/Quick_Start_Guide.md) for installing dependent libraries and how to flash.
|
||||
|
||||
**Note:** Please ensure to use the bsec_interface_multi.h header file specifically, for demonstrating the multi instance feature
|
||||
|
||||
### 5. Tested board/core list
|
||||
|
||||
The current list of tested boards include,
|
||||
|
||||
| Core MCU | Tested boards | Arduino core version | Arduino core repository |
|
||||
|----------|---------------|----------------------|-------------------------|
|
||||
| Esp32 | Adafruit ESP32 Feather | v2.0.3 | https://github.com/espressif/arduino-esp32 |
|
||||
| Esp8266 | Adafruit Feather HUZZAH ESP8266 | v3.0.2 | https://github.com/esp8266/Arduino |
|
||||
|
||||
## Copyright (C) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
# BME688 Development Kit-Firmware-Quick-Start-Guide
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
Follow the Installation and getting started in the [README.md](../../README.md).
|
||||
|
||||
## Instructions to build the **bme68x_demo_sample**
|
||||
|
||||
1. Install the following Arduino libraries under Sketch->Include Library->Manage Libraries
|
||||
|
||||
- ArduinoJson (tested for 6.19.4 by Benoit Blanchon)
|
||||
|
||||
- RTClib (tested for 2.0.3 by Adafruit)
|
||||
|
||||
- Click OK, when asked to install needed dependencies
|
||||
|
||||
- SdFat (tested for 2.1.2 by Bill Greiman)
|
||||
|
||||
2. Open the 'bme68x_demo_sample.ino' file from the path - Bosch_BSEC2_Library/examples/bme68x_demo_sample
|
||||
|
||||
3. Connect your board via USB
|
||||
|
||||
- Select "Adafruit ESP32 Feather" in the Arduino IDE under Tools->Board
|
||||
|
||||
- Select your COM Port under Tools->Port
|
||||
|
||||
5. Upload the firmware
|
||||
|
||||
- If you have a coin cell (CR1220) for the RTC, make sure it is inserted before flashing the board
|
||||
|
||||
- When the board is flashed, don't unmount the coin cell, if not necessary
|
||||
|
||||
5. Wait for the board to be flashed and then disconnect it
|
||||
|
||||
- Last line in the Arduino command line should be: "Hard resetting via RTS pin..."
|
||||
|
||||
6. To start the data logging, insert an SD-card with a '.bmeconfig file' in it (generated using BME AI studio) and connect power supply
|
||||
|
||||
7. A red LED blinking with 1Hz indicates a successful data logging, a faster blinking indicates an error during the initialization (RTC, SD or Bluetooth)
|
||||
|
||||
## Additional Note
|
||||
|
||||
The 'Bosch_BSEC2_Library' has a 'src' folder with the following files essential for running application-
|
||||
|
||||
- header files - bsec_datatypes.h, bsec_interface.h and bsec_interface_multi.h(under folder 'inc')
|
||||
|
||||
- esp32 library - static library (under 'esp32')
|
||||
|
||||
## More about Demo Application Code (Bme68x_demo_sample.ino Sketch):
|
||||
|
||||
This is an example code for datalogging and integration of BSEC2x library in BME688 development kit,
|
||||
which has been designed to work with Adafruit ESP32 Feather Board.
|
||||
|
||||
The example code will primarily operate in two modes-
|
||||
|
||||
**a. DEMO_RECORDING_MODE**
|
||||
|
||||
**b. DEMO_TEST_ALGORITHM_MODE**
|
||||
|
||||
- Multi sensor support is available in DEMO_RECORDING_MODE upto 8 sensors.
|
||||
- Modify NUM_BME68X_UNITS between 0 to 8, where 0 to 7 is for sensor numbers 1 to 8 respectively and 8 is for running all 8 sensors parallely.
|
||||
- Multi sensor support is available in DEMO_TEST_ALGORITHM_MODE upto 4 sensors.
|
||||
- Modify NUM_BME68X_UNITS between 0 to 4, where 0 to 3 is for sensor numbers 1 to 4 respectively and 4 is for running all 4 sensors parallely.
|
||||
|
||||
### Note:
|
||||
|
||||
- After successfully flashing the firmware, "DEMO_RECORDING_MODE" is the default mode set in the example.
|
||||
|
||||
- An initial check for the availability of sensor board configuration file (.bmeconfig) inside SD card is performed.
|
||||
|
||||
- For DEMO_RECORDING_MODE, once .bmeconfig file has been detected, it will initialize and set the heater profiles for all the bme688 sensors with the provided configuration and create bme68x datalogger output file (with '.bmerawdata' extension).
|
||||
|
||||
- Until the user connects the board to the BME688 demo application through Bluetooth LE and switches to "DEMO_TEST_ALGORITHM_MODE", it will continue to collect the data in DEMO_RECORDING_MODE.
|
||||
|
||||
- When it comes to 'DEMO_TEST_ALGORITHM_MODE' (connecting over bluetooth and set to "DEMO_TEST_ALGORITHM_MODE"), initialization of sensor and BSEC library is undertaken.
|
||||
|
||||
- Furthermore, configuring with the BSEC config file (generated out of training through BME AI Studio or a default configuration from the BSEC website release package) and subscribing for the desired virtual outputs with the supported sample rate is complete, an output data file is created with the '.aiprediction' extension.
|
||||
|
||||
- If the Bluetooth is disconnected, the board continuous to work in the existing mode unless power is reset.
|
||||
|
||||
- The default bootup mode is "DEMO_RECORDING_MODE".
|
||||
409
libraries/bsec2/examples/bme68x_demo_sample/ble_controller.cpp
Normal file
409
libraries/bsec2/examples/bme68x_demo_sample/ble_controller.cpp
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file ble_controller.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief ble_controller
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "ble_controller.h"
|
||||
|
||||
bleController::ble_cmd bleController::cmd_list[] = {
|
||||
{"setlabel", &bleController::parse_cmd_set_label, bleController::SET_LABEL},
|
||||
{"setlabelinfo", &bleController::parse_cmd_set_label_info, bleController::SET_LABEL_INFO},
|
||||
{"getlabelinfo", &bleController::parse_cmd_get_label_info, bleController::GET_LABEL_INFO},
|
||||
{"setrtctime", &bleController::parse_cmd_set_rtc_time, bleController::SET_RTC_TIME},
|
||||
{"getrtctime", &bleController::parse_cmd_get_rtc_time, bleController::GET_RTC_TIME},
|
||||
{"start", &bleController::parse_cmd_start_streaming, bleController::START_STREAMING},
|
||||
{"stop", &bleController::parse_cmd_stop_streaming, bleController::STOP_STREAMING},
|
||||
{"readconfig", &bleController::parse_cmd_read_config, bleController::READ_CONFIG},
|
||||
{"setappmode", &bleController::parse_cmd_set_appmode, bleController::SET_APPMODE},
|
||||
{"getappmode", &bleController::parse_cmd_get_appmode, bleController::GET_APPMODE},
|
||||
{"setgroundtruth", &bleController::parse_cmd_set_groundtruth, bleController::SET_GROUNDTRUTH},
|
||||
{"getfwversion", &bleController::parse_cmd_get_fw_version, bleController::GET_FW_VERSION},
|
||||
};
|
||||
|
||||
QueueHandle_t bleController::msg_queue = nullptr;
|
||||
BLECharacteristic *bleController::ble_char_tx = nullptr, *bleController::ble_char_rx = nullptr;
|
||||
BLEServer *bleController::pServer = nullptr;
|
||||
|
||||
/*!
|
||||
* @brief bleController class Constructor
|
||||
*/
|
||||
bleController::bleController(bleCallBack callBack) : _callBack(callBack)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* @brief function to initialize the ble controller
|
||||
*/
|
||||
demo_ret_code bleController::begin()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
|
||||
msg_queue = xQueueCreate(BLE_MSG_QUEUE_LEN, sizeof(ble_msg));
|
||||
|
||||
/* Initialize BLE with Device name */
|
||||
BLEDevice::init("BME688 Development Kit");
|
||||
/* Create Server */
|
||||
pServer = BLEDevice::createServer();
|
||||
pServer->setCallbacks(new serverCallbacks());
|
||||
|
||||
/* Create UART Service */
|
||||
BLEService *pService = pServer->createService(SERVICE_UUID);
|
||||
/* add characteristics for transmitting and receiving */
|
||||
ble_char_tx = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_TX,
|
||||
BLECharacteristic::PROPERTY_NOTIFY
|
||||
);
|
||||
ble_char_tx->addDescriptor(new BLE2902());
|
||||
|
||||
ble_char_rx = pService->createCharacteristic(
|
||||
CHARACTERISTIC_UUID_RX,
|
||||
BLECharacteristic::PROPERTY_WRITE
|
||||
);
|
||||
/* set callback functions */
|
||||
ble_char_rx->setCallbacks(this);
|
||||
/* start advertising */
|
||||
pService->start();
|
||||
pServer->getAdvertising()->start();
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function fetches the RTC time which is requested through ble command
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_get_rtc_time(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
return CMD_VALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function parses the RTC time received from the ble device and updates
|
||||
* the RTC time to the ble structure
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_set_rtc_time(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
uint32_t rtc;
|
||||
|
||||
if (ss >> rtc)
|
||||
{
|
||||
msg.rtc_time = rtc;
|
||||
return CMD_VALID;
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the received label to the ble structure
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_set_label(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
uint32_t label;
|
||||
|
||||
if (ss >> label)
|
||||
{
|
||||
msg.label = label;
|
||||
return CMD_VALID;
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function fetches the current label information
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_get_label_info(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
return CMD_VALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the received label information to the ble structure
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_set_label_info(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
uint32_t label;
|
||||
std::string lbl_name, lbl_desc;
|
||||
|
||||
if (ss >> label)
|
||||
{
|
||||
msg.label_info.label = label;
|
||||
|
||||
/* read label name until comma */
|
||||
if (std::getline(ss, lbl_name, ','))
|
||||
{
|
||||
lbl_name.erase(lbl_name.begin());
|
||||
|
||||
if (lbl_name.length() > LABEL_NAME_SIZE)
|
||||
{
|
||||
return MAX_LABEL_NAME_REACHED;
|
||||
}
|
||||
memset(msg.label_info.label_name, 0, (LABEL_NAME_SIZE + 1));
|
||||
strncpy(msg.label_info.label_name, lbl_name.c_str(), (LABEL_NAME_SIZE - 1));
|
||||
|
||||
/* read label description until dot */
|
||||
if(std::getline(ss, lbl_desc, '.'))
|
||||
{
|
||||
|
||||
if (lbl_desc.length() > LABEL_DESC_SIZE)
|
||||
{
|
||||
return MAX_LABEL_DESCRIPTION_REACHED;
|
||||
}
|
||||
memset(msg.label_info.label_desc, 0, (LABEL_DESC_SIZE + 1));
|
||||
strncpy(msg.label_info.label_desc, lbl_desc.c_str(), (LABEL_DESC_SIZE - 1));
|
||||
return CMD_VALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function launches sensor data or sensor data and BSEC output streaming through ble
|
||||
* based on the app mode
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_start_streaming(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
int32_t sensor_num, sample_rate, output_id;
|
||||
|
||||
if (ss >> sensor_num)
|
||||
{
|
||||
msg.bsec.selected_sensor = static_cast<uint8_t>(sensor_num);
|
||||
|
||||
if (ss >> sample_rate)
|
||||
{
|
||||
msg.bsec.sample_rate = static_cast<uint8_t>(sample_rate);
|
||||
msg.bsec.len = 0;
|
||||
|
||||
while ((msg.bsec.len < BSEC_NUMBER_OUTPUTS) && (ss >> output_id))
|
||||
{
|
||||
msg.bsec.output_id[msg.bsec.len++] = static_cast<uint8_t>(output_id);
|
||||
}
|
||||
|
||||
if (ss >> output_id)
|
||||
{
|
||||
return BSEC_OUTPUT_EXCESS_ERROR;
|
||||
}
|
||||
return CMD_VALID;
|
||||
}
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function stops ble streaming
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_stop_streaming(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
return CMD_VALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function launches the config file data through ble
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_read_config(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
int32_t file_type;
|
||||
|
||||
if (ss >> file_type)
|
||||
{
|
||||
msg.file_type = static_cast<config_file>(file_type);
|
||||
return CMD_VALID;
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the current Appmode
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_set_appmode(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
int32_t mode;
|
||||
|
||||
if (ss >> mode)
|
||||
{
|
||||
msg.mode = static_cast<uint8_t>(mode);
|
||||
return CMD_VALID;
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the current Appmode through ble
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_get_appmode(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
return CMD_VALID;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the Groundtruth
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_set_groundtruth(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
int32_t ground_truth;
|
||||
|
||||
if (ss >> ground_truth)
|
||||
{
|
||||
msg.ground_truth = static_cast<uint32_t>(ground_truth);
|
||||
return CMD_VALID;
|
||||
}
|
||||
return CMD_INVALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the current firmware version through ble
|
||||
*/
|
||||
bleController::cmd_status bleController::parse_cmd_get_fw_version(std::stringstream& ss, ble_msg& msg)
|
||||
{
|
||||
return CMD_VALID;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief function gets called when data is received from a bluetooth device.
|
||||
* It will read in the sent bluetooth command
|
||||
*/
|
||||
void bleController::onWrite(BLECharacteristic *pCharacteristic)
|
||||
{
|
||||
std::string rx_value = pCharacteristic->getValue(), cmd_name;
|
||||
std::stringstream ss(rx_value);
|
||||
cmd_status status = CMD_INVALID;
|
||||
ble_msg msg;
|
||||
|
||||
if (ss >> cmd_name)
|
||||
{
|
||||
StaticJsonDocument<BLE_JSON_DOC_SIZE> jsonDoc;
|
||||
|
||||
for (auto& cmd : cmd_list)
|
||||
{
|
||||
|
||||
if (cmd_name == cmd.name)
|
||||
{
|
||||
status = cmd.parse(ss, msg);
|
||||
|
||||
if (status == CMD_VALID)
|
||||
{
|
||||
msg.name = cmd.name;
|
||||
msg.id = cmd.id;
|
||||
|
||||
if (xQueueSendFromISR(msg_queue, (const void*)&msg, 0) == pdPASS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CONTROLLER_QUEUE_FULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jsonDoc[cmd_name.c_str()] = status;
|
||||
send_notification(jsonDoc);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function checks the ble connection status, restarts advertising if disconnected
|
||||
*/
|
||||
void bleController::check_ble_connection_sts()
|
||||
{
|
||||
/* disconnecting */
|
||||
if (!device_connected && old_device_connected)
|
||||
{
|
||||
pServer->startAdvertising(); /* restart advertising, when ble is disconnected */
|
||||
old_device_connected = device_connected;
|
||||
}
|
||||
/* connecting */
|
||||
if (device_connected && !old_device_connected)
|
||||
{
|
||||
old_device_connected = device_connected;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief function dequeues the last received ble message. The ble callBack is
|
||||
* called if a new message is available.
|
||||
*/
|
||||
bool bleController::dequeue_ble_msg(void)
|
||||
{
|
||||
ble_msg msg;
|
||||
|
||||
if (xQueueReceive(msg_queue, &msg, 0) == pdPASS)
|
||||
{
|
||||
StaticJsonDocument<BLE_JSON_DOC_SIZE> jsonDoc;
|
||||
|
||||
if (_callBack != nullptr)
|
||||
{
|
||||
_callBack(msg, jsonDoc);
|
||||
|
||||
send_notification(jsonDoc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief function to send a json formatted notification
|
||||
*/
|
||||
void bleController::send_notification(JsonDocument& jsonDoc)
|
||||
{
|
||||
String notif, msg;
|
||||
|
||||
serializeJson(jsonDoc, notif);
|
||||
|
||||
size_t not_len = notif.length(), begin_msg = 0, end_msg = BLE_CONTROLLER_NOTIF_SIZE;
|
||||
|
||||
while (begin_msg < not_len)
|
||||
{
|
||||
|
||||
if (end_msg > not_len)
|
||||
{
|
||||
end_msg = not_len;
|
||||
}
|
||||
msg = notif.substring(begin_msg, end_msg);
|
||||
|
||||
begin_msg += BLE_CONTROLLER_NOTIF_SIZE;
|
||||
end_msg += BLE_CONTROLLER_NOTIF_SIZE;
|
||||
|
||||
ble_char_tx->setValue((const char*)msg.c_str());
|
||||
ble_char_tx->notify();
|
||||
}
|
||||
}
|
||||
327
libraries/bsec2/examples/bme68x_demo_sample/ble_controller.h
Normal file
327
libraries/bsec2/examples/bme68x_demo_sample/ble_controller.h
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file ble_controller.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the ble controller
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BLE_CONTROLLER_H
|
||||
#define BLE_CONTROLLER_H
|
||||
|
||||
/* Include Arduino Core */
|
||||
#include <Arduino.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <sstream>
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEServer.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLE2902.h>
|
||||
#include "BLECharacteristic.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include "label_provider.h"
|
||||
#include "demo_app.h"
|
||||
|
||||
/* Bluetooth UART UUID's */
|
||||
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
|
||||
#define BLE_MSG_QUEUE_LEN UINT8_C(3)
|
||||
#define BLE_JSON_DOC_SIZE UINT16_C(2048)
|
||||
#define BLE_CONTROLLER_NOTIF_SIZE UINT16_C(600)
|
||||
#define BLE_MAX_MTU_SIZE UINT16_C(512)
|
||||
|
||||
static bool device_connected = false;
|
||||
static bool old_device_connected = false;
|
||||
|
||||
/*!
|
||||
* @brief Class library for the ble controller
|
||||
*/
|
||||
class bleController: public BLECharacteristicCallbacks
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* @brief ble communication status
|
||||
*/
|
||||
enum cmd_status
|
||||
{
|
||||
CMD_VALID,
|
||||
CMD_INVALID,
|
||||
CONTROLLER_QUEUE_FULL,
|
||||
LABEL_INVALID,
|
||||
BSEC_SELECTED_SENSOR_INVALID,
|
||||
BSEC_CONFIG_FILE_ERROR,
|
||||
BSEC_INIT_ERROR,
|
||||
BSEC_SET_CONFIG_ERROR,
|
||||
BSEC_UPDATE_SUBSCRIPTION_ERROR,
|
||||
BSEC_RUN_ERROR,
|
||||
BSEC_OUTPUT_EXCESS_ERROR,
|
||||
SENSOR_CONFIG_MISSING,
|
||||
SENSOR_INITIALIZATION_FAILED,
|
||||
SD_CARD_INIT_ERROR,
|
||||
CONFIG_FILE_ERROR,
|
||||
APP_ALREADY_IN_STREAMING_MODE,
|
||||
SENSOR_READ_ERROR,
|
||||
BSEC_CONFIG_FILE_MISSING,
|
||||
AI_CONFIG_FILE_MISSING,
|
||||
LABEL_INFO_FILE_MISSING,
|
||||
INVALID_APP_MODE,
|
||||
LABEL_FILE_OPEN_FAILED,
|
||||
MAX_LABEL_NAME_REACHED,
|
||||
MAX_LABEL_DESCRIPTION_REACHED,
|
||||
FILE_OPEN_ERROR,
|
||||
DESERIALIZATION_FAILED,
|
||||
LABEL_NOT_FOUND,
|
||||
AI_CONFIG_AND_SUBSCRIPTION_MISSMATCH
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief bsec sample rate enumeration
|
||||
*/
|
||||
enum bsec_sample_rate
|
||||
{
|
||||
ULP,
|
||||
LP,
|
||||
HP
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief config file type enumeration
|
||||
*/
|
||||
enum config_file
|
||||
{
|
||||
BMECONFIG,
|
||||
AICONFIG
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief bluetooth message id enumeration
|
||||
*/
|
||||
enum ble_msg_id
|
||||
{
|
||||
GET_LABEL_INFO,
|
||||
SET_LABEL_INFO,
|
||||
SET_LABEL,
|
||||
GET_RTC_TIME,
|
||||
SET_RTC_TIME,
|
||||
START_STREAMING,
|
||||
STOP_STREAMING,
|
||||
READ_CONFIG,
|
||||
SET_APPMODE,
|
||||
GET_APPMODE,
|
||||
SET_GROUNDTRUTH,
|
||||
GET_FW_VERSION
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief bluetooth bsec message
|
||||
*/
|
||||
struct ble_bsec_msg
|
||||
{
|
||||
uint8_t selected_sensor;
|
||||
uint8_t sample_rate;
|
||||
uint8_t len;
|
||||
uint8_t output_id[BSEC_NUMBER_OUTPUTS];
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief label information
|
||||
*/
|
||||
struct ble_label_info
|
||||
{
|
||||
uint32_t label;
|
||||
char label_name[LABEL_NAME_SIZE + 1];
|
||||
char label_desc[LABEL_DESC_SIZE + 1];
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* @brief bluetooth message structure
|
||||
*/
|
||||
struct ble_msg
|
||||
{
|
||||
const char *name;
|
||||
ble_msg_id id;
|
||||
union
|
||||
{
|
||||
ble_bsec_msg bsec;
|
||||
uint32_t label;
|
||||
uint32_t rtc_time;
|
||||
config_file file_type;
|
||||
uint8_t mode;
|
||||
ble_label_info label_info;
|
||||
uint32_t ground_truth;
|
||||
};
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief bluetooth command structure
|
||||
*/
|
||||
struct ble_cmd
|
||||
{
|
||||
const char *name;
|
||||
cmd_status (*parse)(std::stringstream& ss, ble_msg& msg);
|
||||
ble_msg_id id;
|
||||
};
|
||||
|
||||
typedef void (*bleCallBack)(const ble_msg &msg, JsonDocument& jsonDoc);
|
||||
|
||||
/*!
|
||||
* @brief : The constructor of the bleController class creates an instance of the class
|
||||
*
|
||||
* @param[in] callBack : ble callBack called when a message is dequeued.
|
||||
*/
|
||||
bleController(bleCallBack callBack);
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes the ble controller.
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code begin();
|
||||
|
||||
/*!
|
||||
* @brief : This function dequeues the last received ble message. The ble callBack
|
||||
* is called if a new message is available.
|
||||
*
|
||||
* @return true if a new message is available else false
|
||||
*/
|
||||
bool dequeue_ble_msg(void);
|
||||
|
||||
/*!
|
||||
* @brief : This function send a json formatted notification.
|
||||
*
|
||||
* @param[out] jsonDoc : json formatted message
|
||||
*/
|
||||
void send_notification(JsonDocument& jsonDoc);
|
||||
|
||||
/*!
|
||||
* @brief : This function gets called when data is received from a bluetooth device.
|
||||
* It will read in the sent bluetooth command.
|
||||
*/
|
||||
void onWrite(BLECharacteristic *pCharacteristic);
|
||||
|
||||
/*!
|
||||
* @brief : This function checks the ble connection status, restarts advertising if disconnected
|
||||
*/
|
||||
void check_ble_connection_sts();
|
||||
|
||||
private:
|
||||
bleCallBack _callBack;
|
||||
|
||||
static QueueHandle_t msg_queue;
|
||||
static ble_cmd cmd_list[];
|
||||
static BLECharacteristic *ble_char_tx, *ble_char_rx;
|
||||
static BLEServer *pServer;
|
||||
|
||||
/*!
|
||||
* @brief : This function fetches the RTC time which is requested through ble command
|
||||
*/
|
||||
static cmd_status parse_cmd_get_rtc_time(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function parses the RTC time received from the ble device and updates
|
||||
* the RTC time to the ble structure
|
||||
*/
|
||||
static cmd_status parse_cmd_set_rtc_time(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function fetches the current label information from the .bmelabelinfo file
|
||||
*/
|
||||
static cmd_status parse_cmd_get_label_info(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the received label information to the ble structure
|
||||
*/
|
||||
static cmd_status parse_cmd_set_label_info(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the received label to the ble structure
|
||||
*/
|
||||
static cmd_status parse_cmd_set_label(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function launches sensor data or sensor data and BSEC output streaming through ble
|
||||
* based on the app mode
|
||||
*/
|
||||
static cmd_status parse_cmd_start_streaming(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function stops ble streaming
|
||||
*/
|
||||
static cmd_status parse_cmd_stop_streaming(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function launches the config file data through ble
|
||||
*/
|
||||
static cmd_status parse_cmd_read_config(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the current Appmode
|
||||
*/
|
||||
static cmd_status parse_cmd_set_appmode(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the current Appmode through ble
|
||||
*/
|
||||
static cmd_status parse_cmd_get_appmode(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the Groundtruth through ble
|
||||
*/
|
||||
static cmd_status parse_cmd_set_groundtruth(std::stringstream& ss, ble_msg& msg);
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the current firmware version through ble
|
||||
*/
|
||||
static cmd_status parse_cmd_get_fw_version(std::stringstream& ss, ble_msg& msg);
|
||||
};
|
||||
|
||||
class serverCallbacks: public BLEServerCallbacks
|
||||
{
|
||||
void onConnect(BLEServer* pServer)
|
||||
{
|
||||
device_connected = true;
|
||||
}
|
||||
|
||||
void onDisconnect(BLEServer* pServer)
|
||||
{
|
||||
device_connected = false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bme68x_datalogger.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief bme68x_datalogger
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "bme68x_datalogger.h"
|
||||
#include <Esp.h>
|
||||
|
||||
/*!
|
||||
* @brief The constructor of the bme68xDataLogger class
|
||||
*/
|
||||
bme68xDataLogger::bme68xDataLogger() : _file_counter(1)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* @brief Function to configure the datalogger using the provided sensor config file
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::begin(const String& config_name)
|
||||
{
|
||||
demo_ret_code ret_code = utils::begin();
|
||||
|
||||
_config_name = config_name;
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
/* Resets the file counter when seed file is generated */
|
||||
_file_counter = 1;
|
||||
ret_code = create_log_file();
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_label_info_file();
|
||||
}
|
||||
_ss.setf(std::ios::fixed, std::ios::floatfield);
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function which flushes the buffered sensor data to the current log file
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::flush()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
File logFile;
|
||||
std::string txt;
|
||||
|
||||
if (_ss.rdbuf()->in_avail())
|
||||
{
|
||||
txt = _ss.str();
|
||||
_ss.str(std::string());
|
||||
|
||||
if (_file_counter && logFile.open(_log_file_name.c_str(), O_RDWR | O_AT_END))
|
||||
{
|
||||
logFile.seek(_sensor_data_pos);
|
||||
logFile.print(txt.c_str());
|
||||
_sensor_data_pos = logFile.position();
|
||||
logFile.println("\n\t ]\n\t}\n}");
|
||||
|
||||
if (logFile.size() >= FILE_SIZE_LIMIT)
|
||||
{
|
||||
logFile.close();
|
||||
++_file_counter;
|
||||
ret_code = create_log_file();
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_label_info_file();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function writes the sensor data to the current log file
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::write_sensor_data(const uint8_t* num, const uint32_t* sensor_id, const uint8_t* sensorMode,
|
||||
const bme68x_data* bme68xData, const uint32_t* scan_cycle_index,
|
||||
gas_label label, demo_ret_code code)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
uint32_t rtc_tsp = utils::get_rtc().now().unixtime();
|
||||
uint32_t time_since_power_on = millis();
|
||||
|
||||
if (_end_of_line)
|
||||
{
|
||||
_ss << ",\n";
|
||||
}
|
||||
_ss << "\t\t\t[\n\t\t\t\t";
|
||||
(num != nullptr) ? (_ss << (uint32_t)*num) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(sensor_id != nullptr) ? (_ss << (uint32_t)*sensor_id) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
_ss << time_since_power_on;
|
||||
_ss << ",\n\t\t\t\t";
|
||||
_ss << rtc_tsp;
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_ss << bme68xData->temperature) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_ss << (bme68xData->pressure * .01f)) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_ss << bme68xData->humidity) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_ss << bme68xData->gas_resistance) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_ss << (uint32_t)bme68xData->gas_index) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
_ss << (bool)(BME68X_PARALLEL_MODE);
|
||||
_ss << ",\n\t\t\t\t";
|
||||
(scan_cycle_index != nullptr) ? (_ss << (uint32_t)(*scan_cycle_index)) : (_ss << "null");
|
||||
_ss << ",\n\t\t\t\t";
|
||||
_ss << (uint32_t)label;
|
||||
_ss << ",\n\t\t\t\t";
|
||||
_ss << (uint32_t)code;
|
||||
_ss << "\n\t\t\t]";
|
||||
|
||||
_end_of_line = true;
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function stores the labelTag, labelName and labelDescription to the .bmelabelinfo file
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::set_label_info(int32_t label_tag, const String& label_name, const String& label_desc)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
|
||||
File logFile;
|
||||
|
||||
if (logFile.open(_label_file_name.c_str(), O_READ))
|
||||
{
|
||||
DeserializationError error = deserializeJson(label_doc, logFile);
|
||||
logFile.close();
|
||||
|
||||
if (error)
|
||||
{
|
||||
Serial.println(error.c_str());
|
||||
return EDK_SENSOR_MANAGER_JSON_DESERIAL_ERROR;
|
||||
}
|
||||
JsonArray lblInfo = label_doc["labelInformation"].as<JsonArray>();
|
||||
|
||||
JsonObject obj = lblInfo.createNestedObject();
|
||||
obj["labelTag"] = label_tag;
|
||||
obj["labelName"] = label_name;
|
||||
obj["labelDescription"] = label_desc;
|
||||
|
||||
if (logFile.open(_label_file_name.c_str(), O_RDWR | O_TRUNC))
|
||||
{
|
||||
serializeJsonPretty(label_doc, logFile);
|
||||
logFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LABEL_INFO_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LABEL_INFO_FILE_ERROR;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function to create a bme68x datalogger output file with .bmerawdata extension
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::create_log_file()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
String mac_str = utils::get_mac_address();
|
||||
String log_file_base_name = "_Board_" + mac_str + "_PowerOnOff_1_";
|
||||
|
||||
_log_file_name = utils::get_date_time() + log_file_base_name + utils::get_file_seed() +
|
||||
"_File_" + String(_file_counter) + BME68X_RAWDATA_FILE_EXT;
|
||||
|
||||
File configFile, logFile;
|
||||
|
||||
if (_config_name.length() && !configFile.open(_config_name.c_str(), O_RDWR))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_SENSOR_CONFIG_FILE_ERROR;
|
||||
}
|
||||
else if (!logFile.open(_log_file_name.c_str(), O_RDWR | O_CREAT))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_config_name.length())
|
||||
{
|
||||
String line_buffer;
|
||||
|
||||
/* read in each line from the config file and copy it to the log file */
|
||||
while (configFile.available())
|
||||
{
|
||||
line_buffer = configFile.readStringUntil('\n');
|
||||
|
||||
/* skip the last closing curly bracket of the JSON document */
|
||||
if (line_buffer == "}")
|
||||
{
|
||||
logFile.println("\t,");
|
||||
break;
|
||||
}
|
||||
logFile.println(line_buffer);
|
||||
}
|
||||
configFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile.println("{");
|
||||
}
|
||||
|
||||
/* write data header / skeleton */
|
||||
/* raw data header */
|
||||
logFile.println("\t\"rawDataHeader\": {");
|
||||
logFile.println("\t\t\"counterPowerOnOff\": 1,");
|
||||
logFile.println("\t\t\"seedPowerOnOff\": \"" + utils::get_file_seed() + "\",");
|
||||
logFile.println("\t\t\"counterFileLimit\": " + String(_file_counter) + ",");
|
||||
logFile.println("\t\t\"dateCreated\": \"" + String(utils::get_rtc().now().unixtime()) + "\",");
|
||||
logFile.println("\t\t\"dateCreated_ISO\": \"" + utils::get_rtc().now().timestamp() + "+00:00\",");
|
||||
logFile.println("\t\t\"firmwareVersion\": \"" + String(FIRMWARE_VERSION) + "\",");
|
||||
logFile.println("\t\t\"boardId\": \"" + mac_str + "\"");
|
||||
logFile.println("\t},");
|
||||
logFile.println("\t\"rawDataBody\": {");
|
||||
logFile.println("\t\t\"dataColumns\": [");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 1");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor ID\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_id\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 2");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Time Since PowerOn\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Milliseconds\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"timestamp_since_poweron\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 3");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Real time clock\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Unix Timestamp: seconds since Jan 01 1970. (UTC); 0 = missing\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"real_time_clock\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 4");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Temperature\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"DegreesCelcius\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"temperature\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 5");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Pressure\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Hectopascals\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"pressure\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 6");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Relative Humidity\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Percent\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"relative_humidity\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 7");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Resistance Gassensor\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Ohms\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"resistance_gassensor\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 8");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Heater Profile Step Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"heater_profile_step_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 9");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Scanning Mode Enabled\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"boolean\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"scanning_enabled\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 10");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Scanning Cycle Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"scanning_cycle_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 11");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Label Tag\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"label_tag\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 12");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Error Code\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"error_code\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 13");
|
||||
logFile.println("\t\t\t}");
|
||||
logFile.println("\t\t],");
|
||||
|
||||
/* data block */
|
||||
logFile.println("\t\t\"dataBlock\": [");
|
||||
/* save position in file, where to write the first data set */
|
||||
_sensor_data_pos = logFile.position();
|
||||
logFile.println("\t\t]");
|
||||
logFile.println("\t}");
|
||||
logFile.println("}");
|
||||
|
||||
/* close log file */
|
||||
logFile.close();
|
||||
|
||||
_end_of_line = false;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function to create a bme68x label information file with .bmelabelinfo extension
|
||||
*/
|
||||
demo_ret_code bme68xDataLogger::create_label_info_file()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
String mac_str = utils::get_mac_address();
|
||||
String label_file_base_name = "_Board_" + mac_str + "_PowerOnOff_1_";
|
||||
|
||||
_label_file_name = utils::get_date_time() + label_file_base_name + utils::get_file_seed() +
|
||||
"_File_" + String(_file_counter) + BME68X_LABEL_INFO_FILE_EXT;
|
||||
File logFile;
|
||||
|
||||
if (!logFile.open(_label_file_name.c_str(), O_RDWR | O_CREAT))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LABEL_INFO_FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write labelinfo header / skeleton */
|
||||
logFile.println("{");
|
||||
logFile.println("\t\"labelInfoHeader\": {");
|
||||
logFile.println("\t\t\"counterPowerOnOff\": 1,");
|
||||
logFile.println("\t\t\"seedPowerOnOff\": \"" + utils::get_file_seed() + "\",");
|
||||
logFile.println("\t\t\"dateCreated\": \"" + String(utils::get_rtc().now().unixtime()) + "\",");
|
||||
logFile.println("\t\t\"dateCreated_ISO\": \"" + utils::get_rtc().now().timestamp() + "+00:00\",");
|
||||
logFile.println("\t\t\"firmwareVersion\": \"" + String(FIRMWARE_VERSION) + "\",");
|
||||
logFile.println("\t\t\"boardId\": \"" + mac_str + "\"");
|
||||
logFile.println("\t},");
|
||||
logFile.println("\t\"labelInformation\": [");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 0,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Initial\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for no label has been set\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 1,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 1\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 1 pressed\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 2,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 2\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 2 pressed\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 3,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 1+2\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 1 and button 2 pressed\"");
|
||||
logFile.print("\t\t}");
|
||||
logFile.println("\n\t]");
|
||||
logFile.print("}");
|
||||
|
||||
/* close log file */
|
||||
logFile.close();
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
137
libraries/bsec2/examples/bme68x_demo_sample/bme68x_datalogger.h
Normal file
137
libraries/bsec2/examples/bme68x_demo_sample/bme68x_datalogger.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bme68x_datalogger.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the bme68x datalogger
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BME68X_DATALOGGER_H
|
||||
#define BME68X_DATALOGGER_H
|
||||
|
||||
/* Include of Arduino Core */
|
||||
#include "Arduino.h"
|
||||
#include <SdFat.h>
|
||||
#include <RTClib.h>
|
||||
#include <base64.h>
|
||||
#include "utils.h"
|
||||
#include "demo_app.h"
|
||||
#include "label_provider.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#define DOC_SIZE UINT32_C(50000)
|
||||
|
||||
/*!
|
||||
* @brief : Class library that holds functionality of the bme68x datalogger
|
||||
*/
|
||||
class bme68xDataLogger
|
||||
{
|
||||
private:
|
||||
String _config_name, _log_file_name, _label_file_name;
|
||||
std::stringstream _ss;
|
||||
uint32_t _sensor_data_pos = 0;
|
||||
uint32_t _file_counter = 1;
|
||||
bool _end_of_line = false;
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a bme68x datalogger output file with .bmerawdata extension
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code create_log_file();
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a bme68x label information file with .bmelabelinfo extension
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code create_label_info_file();
|
||||
public:
|
||||
StaticJsonDocument<DOC_SIZE> label_doc;
|
||||
|
||||
/*!
|
||||
* @brief : The constructor of the bme68xDataLogger class
|
||||
* Creates an instance of the class
|
||||
*/
|
||||
bme68xDataLogger();
|
||||
|
||||
/*!
|
||||
* @brief : This function configures the datalogger using the provided sensor config file
|
||||
*
|
||||
* @param[in] configName : sensor configuration file
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code begin(const String& configName = "");
|
||||
|
||||
/*!
|
||||
* @brief : This function flushes the buffered sensor data to the current log file
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code flush();
|
||||
|
||||
/*!
|
||||
* @brief : This function writes the sensor data to the current log file.
|
||||
*
|
||||
* @param[in] num : sensor number
|
||||
* @param[in] sensorId : pointer to sensor id, if NULL a null json object is inserted
|
||||
* @param[in] sensorMode : pointer to sensor operation mode, if NULL a null json object is inserted
|
||||
* @param[in] bme68xData : pointer to bme68x data, if NULL a null json object is inserted
|
||||
* @param[in] scanCycleIndex : pointer to sensor scanning cycle index
|
||||
* @param[in] label : class label
|
||||
* @param[in] code : application return code
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code write_sensor_data(const uint8_t* num, const uint32_t* sensor_id, const uint8_t* sensor_mode,
|
||||
const bme68x_data* bme68xData, const uint32_t* scan_cycle_index,
|
||||
gas_label label, demo_ret_code code);
|
||||
/*!
|
||||
* @brief : This function stores the labelTag, labelName and labelDescription to the .bmelabelinfo file.
|
||||
*
|
||||
* @param[in] labelTag : label tag
|
||||
* @param[in] labelName : reference to the label name
|
||||
* @param[in] labelDesc : reference to the label description
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code set_label_info(int32_t label_tag,const String& label_name, const String& label_desc);
|
||||
};
|
||||
|
||||
#endif
|
||||
1088
libraries/bsec2/examples/bme68x_demo_sample/bme68x_demo_sample.ino
Normal file
1088
libraries/bsec2/examples/bme68x_demo_sample/bme68x_demo_sample.ino
Normal file
File diff suppressed because it is too large
Load diff
988
libraries/bsec2/examples/bme68x_demo_sample/bsec_datalogger.cpp
Normal file
988
libraries/bsec2/examples/bme68x_demo_sample/bsec_datalogger.cpp
Normal file
|
|
@ -0,0 +1,988 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bsec_datalogger.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief bsec_datalogger
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "bsec_datalogger.h"
|
||||
#include <math.h>
|
||||
#include <Esp.h>
|
||||
|
||||
StaticJsonDocument<80> filter1;
|
||||
StaticJsonDocument<1024> doc;
|
||||
StaticJsonDocument<70> filter2;
|
||||
StaticJsonDocument<512> label_doc;
|
||||
StaticJsonDocument<2048> config;
|
||||
|
||||
/*!
|
||||
* @brief The constructor of the bsec_datalogger class
|
||||
*/
|
||||
bsecDataLogger::bsecDataLogger() : _bsec_file_counter(1)
|
||||
{}
|
||||
|
||||
/*!
|
||||
* @brief This function configures the bsec datalogger using the provided bsec config string file
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::begin(const String& config_name, const bsec_version_t& bsec_version, uint8_t sensor_num)
|
||||
{
|
||||
demo_ret_code ret_code = utils::begin();
|
||||
|
||||
_ai_config_name = config_name;
|
||||
_version = bsec_version;
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_bsec_file();
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_raw_data_file(sensor_num);
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_label_info_file();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function creates a bsec output file
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::create_bsec_file()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
String mac_str = utils::get_mac_address();
|
||||
String ai_file_base_name = "_Board_" + mac_str + "_PowerOnOff_1_";
|
||||
|
||||
_ai_file_name = utils::get_date_time() + ai_file_base_name + utils::get_file_seed() + "_File_" +
|
||||
String(_bsec_file_counter) + AI_DATA_FILE_EXT;
|
||||
|
||||
File configFile, logFile;
|
||||
|
||||
if (_ai_config_name.length() && !configFile.open(_ai_config_name.c_str(), O_RDWR))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_AI_CONFIG_FILE_ERROR;
|
||||
}
|
||||
else if (!logFile.open(_ai_file_name.c_str(), O_RDWR | O_CREAT))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (_ai_config_name.length())
|
||||
{
|
||||
String line_buffer;
|
||||
|
||||
/* read in each line from the config file and copy it to the log file */
|
||||
while (configFile.available())
|
||||
{
|
||||
line_buffer = configFile.readStringUntil('\n');
|
||||
|
||||
/* skip the last closing curly bracket of the JSON document */
|
||||
if (line_buffer == "}")
|
||||
{
|
||||
logFile.println("\t,");
|
||||
break;
|
||||
}
|
||||
logFile.println(line_buffer);
|
||||
}
|
||||
configFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile.println("{");
|
||||
}
|
||||
logFile.println("\t\"aiPredictionsDataHeader\": {");
|
||||
logFile.println("\t\t\"counterPowerOnOff\": 1,");
|
||||
logFile.println("\t\t\"seedPowerOnOff\": \"" + utils::get_file_seed() + "\",");
|
||||
logFile.println("\t\t\"counterFileLimit\": " + String(_bsec_file_counter) + ",");
|
||||
logFile.println("\t\t\"dateCreated\": \"" + String(utils::get_rtc().now().unixtime()) + "\",");
|
||||
logFile.println("\t\t\"dateCreated_ISO\": \"" + utils::get_rtc().now().timestamp() + "+00:00\",");
|
||||
logFile.println("\t\t\"firmwareVersion\": \"" + String(FIRMWARE_VERSION) + "\",");
|
||||
logFile.println("\t\t\"bsecVersion\": \"" + String(_version.major) + "." + String(_version.minor) + \
|
||||
"." + String(_version.major_bugfix) + "." + String(_version.minor_bugfix) + "\",");
|
||||
logFile.println("\t\t\"boardId\": \"" + mac_str + "\"");
|
||||
logFile.println("\t},");
|
||||
logFile.println("\t\"aiPredictionsDataBody\": {");
|
||||
logFile.println("\t\t\"dataColumns\": [");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 1");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor ID\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_id\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 2");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Start Time Since PowerOn\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Milliseconds\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"start_time_since_poweron\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 3");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"End Time Since PowerOn\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Milliseconds\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"end_time_since_poweron\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 4");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Class/Target 1 prediction\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"classtarget_1_prediction\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 5");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Class/Target 2 prediction\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"classtarget_2_prediction\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 6");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Class/Target 3 prediction\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"classtarget_3_prediction\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 7");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Class/Target 4 prediction\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"classtarget_4_prediction\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 8");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Prediction accuracy\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"prediction_accuracy\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 9");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"IAQ\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"iaq\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 10");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"IAQ accuracy\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"iaq_accuracy\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 11");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Error code\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"error_code\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 12");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Ground truth\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"classId\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"ground_truth\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 13");
|
||||
logFile.println("\t\t\t}");
|
||||
logFile.println("\t\t],");
|
||||
|
||||
/* data block */
|
||||
logFile.println("\t\t\"dataBlock\": [");
|
||||
/* save position in file, where to write the first data set */
|
||||
_ai_data_pos = logFile.position();
|
||||
logFile.println("\t\t]");
|
||||
logFile.println("\t}");
|
||||
logFile.println("}");
|
||||
|
||||
/* close log file */
|
||||
logFile.close();
|
||||
|
||||
_first_line = true;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function creates a bme68x datalogger output file
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::create_raw_data_file(uint8_t sensor_num)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
String mac_str = utils::get_mac_address();
|
||||
String bme_file_base_name = "_Board_" + mac_str + "_PowerOnOff_1_";
|
||||
|
||||
_bme_file_name = utils::get_date_time() + bme_file_base_name + utils::get_file_seed() + "_File_" +
|
||||
String(_bsec_file_counter) + BME68X_RAWDATA_FILE_EXT;
|
||||
|
||||
File logFile;
|
||||
|
||||
if (!logFile.open(_bme_file_name.c_str(), O_RDWR | O_CREAT))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = prepare_config_content(sensor_num);
|
||||
|
||||
if (ret_code != EDK_OK)
|
||||
{
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/* Writes the config header and body to the logfile */
|
||||
logFile.print(config_string);
|
||||
/* write data header / skeleton */
|
||||
/* raw data header */
|
||||
logFile.println("\t,\n\t\"rawDataHeader\": {");
|
||||
logFile.println("\t\t\"counterPowerOnOff\": 1,");
|
||||
logFile.println("\t\t\"seedPowerOnOff\": \"" + utils::get_file_seed() + "\",");
|
||||
logFile.println("\t\t\"counterFileLimit\": " + String(_bsec_file_counter) + ",");
|
||||
logFile.println("\t\t\"dateCreated\": \"" + String(utils::get_rtc().now().unixtime()) + "\",");
|
||||
logFile.println("\t\t\"dateCreated_ISO\": \"" + utils::get_rtc().now().timestamp() + "+00:00\",");
|
||||
logFile.println("\t\t\"firmwareVersion\": \"" + String(FIRMWARE_VERSION) + "\",");
|
||||
logFile.println("\t\t\"boardId\": \"" + mac_str + "\"");
|
||||
logFile.println("\t},");
|
||||
logFile.println("\t\"rawDataBody\": {");
|
||||
logFile.println("\t\t\"dataColumns\": [");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 1");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Sensor ID\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"sensor_id\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 2");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Time Since PowerOn\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Milliseconds\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"timestamp_since_poweron\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 3");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Real time clock\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Unix Timestamp: seconds since Jan 01 1970. (UTC); 0 = missing\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"real_time_clock\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 4");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Temperature\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"DegreesCelcius\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"temperature\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 5");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Pressure\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Hectopascals\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"pressure\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 6");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Relative Humidity\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Percent\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"relative_humidity\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 7");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Resistance Gassensor\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"Ohms\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"float\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"resistance_gassensor\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 8");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Heater Profile Step Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"heater_profile_step_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 9");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Scanning Mode Enabled\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"boolean\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"scanning_enabled\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 10");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Scanning Cycle Index\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"scanning_cycle_index\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 11");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Label Tag\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"label_tag\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 12");
|
||||
logFile.println("\t\t\t},");
|
||||
logFile.println("\t\t\t{");
|
||||
logFile.println("\t\t\t\t\"name\": \"Error Code\",");
|
||||
logFile.println("\t\t\t\t\"unit\": \"\",");
|
||||
logFile.println("\t\t\t\t\"format\": \"integer\",");
|
||||
logFile.println("\t\t\t\t\"key\": \"error_code\",");
|
||||
logFile.println("\t\t\t\t\"colId\": 13");
|
||||
logFile.println("\t\t\t}");
|
||||
logFile.println("\t\t],");
|
||||
|
||||
/* data block */
|
||||
logFile.println("\t\t\"dataBlock\": [");
|
||||
/* save position in file, where to write the first data set */
|
||||
_bme_data_pos = logFile.position();
|
||||
logFile.println("\t\t]");
|
||||
logFile.println("\t}");
|
||||
logFile.println("}");
|
||||
|
||||
_end_of_line = false;
|
||||
/* close log file */
|
||||
logFile.close();
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
demo_ret_code bsecDataLogger::prepare_config_content(uint8_t sensor_num)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
filter1.clear();
|
||||
doc.clear();
|
||||
config.clear();
|
||||
config_string = "\0";
|
||||
|
||||
File configFile;
|
||||
|
||||
if (_ai_config_name.length() && !configFile.open(_ai_config_name.c_str(), O_RDWR))
|
||||
{
|
||||
return EDK_DATALOGGER_AI_CONFIG_FILE_ERROR;
|
||||
}
|
||||
|
||||
filter1["aiConfigHeader"]["appVersion"] = true;
|
||||
JsonObject aiConfigBody = filter1.createNestedObject("aiConfigBody");
|
||||
aiConfigBody["heaterProfile"] = true;
|
||||
aiConfigBody["dutyCycleProfile"] = true;
|
||||
|
||||
DeserializationError error = deserializeJson(doc, configFile, DeserializationOption::Filter(filter1));
|
||||
|
||||
if (error)
|
||||
{
|
||||
Serial.println(error.c_str());
|
||||
return EDK_SENSOR_MANAGER_JSON_DESERIAL_ERROR;
|
||||
}
|
||||
|
||||
/* parcing configuration details from aiConfig file in to local buffers */
|
||||
const char* app_version = doc["aiConfigHeader"]["appVersion"];
|
||||
|
||||
JsonObject heaterProfile = doc["aiConfigBody"]["heaterProfile"];
|
||||
const char* heater_profile_id = heaterProfile["id"];
|
||||
int32_t heater_profile_time_base = heaterProfile["timeBase"];
|
||||
|
||||
JsonArray tempTimeVector = heaterProfile["temperatureTimeVectors"];
|
||||
|
||||
int32_t temp_time_vector_0_0 = tempTimeVector[0][0];
|
||||
int32_t temp_time_vector_0_1 = tempTimeVector[0][1];
|
||||
|
||||
int32_t temp_time_vector_1_0 = tempTimeVector[1][0];
|
||||
int32_t temp_time_vector_1_1 = tempTimeVector[1][1];
|
||||
|
||||
int32_t temp_time_vector_2_0 = tempTimeVector[2][0];
|
||||
int32_t temp_time_vector_2_1 = tempTimeVector[2][1];
|
||||
|
||||
int32_t temp_time_vector_3_0 = tempTimeVector[3][0];
|
||||
int32_t temp_time_vector_3_1 = tempTimeVector[3][1];
|
||||
|
||||
int32_t temp_time_vector_4_0 = tempTimeVector[4][0];
|
||||
int32_t temp_time_vector_4_1 = tempTimeVector[4][1];
|
||||
|
||||
int32_t temp_time_vector_5_0 = tempTimeVector[5][0];
|
||||
int32_t temp_time_vector_5_1 = tempTimeVector[5][1];
|
||||
|
||||
int32_t temp_time_vector_6_0 = tempTimeVector[6][0];
|
||||
int32_t temp_time_vector_6_1 = tempTimeVector[6][1];
|
||||
|
||||
int32_t temp_time_vector_7_0 = tempTimeVector[7][0];
|
||||
int32_t temp_time_vector_7_1 = tempTimeVector[7][1];
|
||||
|
||||
int32_t temp_time_vector_8_0 = tempTimeVector[8][0];
|
||||
int32_t temp_time_vector_8_1 = tempTimeVector[8][1];
|
||||
|
||||
int32_t temp_time_vector_9_0 = tempTimeVector[9][0];
|
||||
int32_t temp_time_vector_9_1 = tempTimeVector[9][1];
|
||||
|
||||
JsonObject dutyCycleProfile = doc["aiConfigBody"]["dutyCycleProfile"];
|
||||
const char* duty_cycle_profile_id = dutyCycleProfile["id"];
|
||||
int32_t number_scanning_cycles = dutyCycleProfile["numberScanningCycles"];
|
||||
int32_t number_sleeping_cycles = dutyCycleProfile["numberSleepingCycles"];
|
||||
|
||||
/* creating configuration header and body */
|
||||
JsonObject configHeader = config.createNestedObject("configHeader");
|
||||
configHeader["dateCreated_ISO"] = utils::get_rtc().now().timestamp() + "+00:00";
|
||||
configHeader["appVersion"] = app_version;
|
||||
configHeader["boardType"] = "board_8";
|
||||
configHeader["boardMode"] = "live_test_algorithm";
|
||||
configHeader["boardLayout"] = "custom";
|
||||
|
||||
JsonObject configBody = config.createNestedObject("configBody");
|
||||
|
||||
JsonObject heaterProfiles = configBody["heaterProfiles"].createNestedObject();
|
||||
heaterProfiles["id"] = heater_profile_id;
|
||||
heaterProfiles["timeBase"] = heater_profile_time_base;
|
||||
|
||||
JsonArray tempTimeVectors = heaterProfiles.createNestedArray("temperatureTimeVectors");
|
||||
|
||||
JsonArray tempTimeVectors_0 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_0.add(temp_time_vector_0_0);
|
||||
tempTimeVectors_0.add(temp_time_vector_0_1);
|
||||
|
||||
JsonArray tempTimeVectors_1 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_1.add(temp_time_vector_1_0);
|
||||
tempTimeVectors_1.add(temp_time_vector_1_1);
|
||||
|
||||
JsonArray tempTimeVectors_2 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_2.add(temp_time_vector_2_0);
|
||||
tempTimeVectors_2.add(temp_time_vector_2_1);
|
||||
|
||||
JsonArray tempTimeVectors_3 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_3.add(temp_time_vector_3_0);
|
||||
tempTimeVectors_3.add(temp_time_vector_3_1);
|
||||
|
||||
JsonArray tempTimeVectors_4 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_4.add(temp_time_vector_4_0);
|
||||
tempTimeVectors_4.add(temp_time_vector_4_1);
|
||||
|
||||
JsonArray tempTimeVectors_5 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_5.add(temp_time_vector_5_0);
|
||||
tempTimeVectors_5.add(temp_time_vector_5_1);
|
||||
|
||||
JsonArray tempTimeVectors_6 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_6.add(temp_time_vector_6_0);
|
||||
tempTimeVectors_6.add(temp_time_vector_6_1);
|
||||
|
||||
JsonArray tempTimeVectors_7 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_7.add(temp_time_vector_7_0);
|
||||
tempTimeVectors_7.add(temp_time_vector_7_1);
|
||||
|
||||
JsonArray tempTimeVectors_8 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_8.add(temp_time_vector_8_0);
|
||||
tempTimeVectors_8.add(temp_time_vector_8_1);
|
||||
|
||||
JsonArray tempTimeVectors_9 = tempTimeVectors.createNestedArray();
|
||||
tempTimeVectors_9.add(temp_time_vector_9_0);
|
||||
tempTimeVectors_9.add(temp_time_vector_9_1);
|
||||
|
||||
JsonArray configBody_dutyCycleProfiles = configBody.createNestedArray("dutyCycleProfiles");
|
||||
|
||||
JsonObject dutyCycleProfiles = configBody_dutyCycleProfiles.createNestedObject();
|
||||
dutyCycleProfiles["id"] = duty_cycle_profile_id;
|
||||
dutyCycleProfiles["numberScanningCycles"] = number_scanning_cycles;
|
||||
dutyCycleProfiles["numberSleepingCycles"] = number_sleeping_cycles;
|
||||
|
||||
JsonArray sensorConfigurations = configBody.createNestedArray("sensorConfigurations");
|
||||
|
||||
JsonObject sensorConfiguration_0 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_0["sensorIndex"] = 0;
|
||||
|
||||
if ( (sensorConfiguration_0["sensorIndex"] == sensor_num) || (sensor_num == NUM_OF_SENS) )
|
||||
{
|
||||
sensorConfiguration_0["active"] = true;
|
||||
sensorConfiguration_0["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_0["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_0["active"] = false;
|
||||
sensorConfiguration_0["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_0["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_1 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_1["sensorIndex"] = 1;
|
||||
|
||||
if ( (sensorConfiguration_1["sensorIndex"] == sensor_num) || (sensor_num == NUM_OF_SENS) )
|
||||
{
|
||||
sensorConfiguration_1["active"] = true;
|
||||
sensorConfiguration_1["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_1["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_1["active"] = false;
|
||||
sensorConfiguration_1["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_1["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_2 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_2["sensorIndex"] = 2;
|
||||
|
||||
if ( (sensorConfiguration_2["sensorIndex"] == sensor_num) || (sensor_num == NUM_OF_SENS) )
|
||||
{
|
||||
sensorConfiguration_2["active"] = true;
|
||||
sensorConfiguration_2["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_2["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_2["active"] = false;
|
||||
sensorConfiguration_2["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_2["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_3 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_3["sensorIndex"] = 3;
|
||||
|
||||
if ( (sensorConfiguration_3["sensorIndex"] == sensor_num) || (sensor_num == NUM_OF_SENS) )
|
||||
{
|
||||
sensorConfiguration_3["active"] = true;
|
||||
sensorConfiguration_3["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_3["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_3["active"] = false;
|
||||
sensorConfiguration_3["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_3["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
/* Sensor number 4 in start command is used to test sensors 0 - 3 in multi instance mode*/
|
||||
JsonObject sensorConfiguration_4 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_4["sensorIndex"] = 4;
|
||||
|
||||
if ( (sensorConfiguration_4["sensorIndex"] == sensor_num) && (sensor_num != NUM_OF_SENS) )
|
||||
{
|
||||
sensorConfiguration_4["active"] = true;
|
||||
sensorConfiguration_4["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_4["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_4["active"] = false;
|
||||
sensorConfiguration_4["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_4["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_5 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_5["sensorIndex"] = 5;
|
||||
|
||||
if (sensorConfiguration_5["sensorIndex"] == sensor_num)
|
||||
{
|
||||
sensorConfiguration_5["active"] = true;
|
||||
sensorConfiguration_5["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_5["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_5["active"] = false;
|
||||
sensorConfiguration_5["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_5["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_6 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_6["sensorIndex"] = 6;
|
||||
|
||||
if (sensorConfiguration_6["sensorIndex"] == sensor_num)
|
||||
{
|
||||
sensorConfiguration_6["active"] = true;
|
||||
sensorConfiguration_6["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_6["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_6["active"] = false;
|
||||
sensorConfiguration_6["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_6["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
|
||||
JsonObject sensorConfiguration_7 = sensorConfigurations.createNestedObject();
|
||||
sensorConfiguration_7["sensorIndex"] = 7;
|
||||
|
||||
if (sensorConfiguration_7["sensorIndex"] == sensor_num)
|
||||
{
|
||||
sensorConfiguration_7["active"] = true;
|
||||
sensorConfiguration_7["heaterProfile"] = heater_profile_id;
|
||||
sensorConfiguration_7["dutyCycleProfile"] = duty_cycle_profile_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorConfiguration_7["active"] = false;
|
||||
sensorConfiguration_7["heaterProfile"] = (char*)0;
|
||||
sensorConfiguration_7["dutyCycleProfile"] = (char*)0;
|
||||
}
|
||||
serializeJsonPretty(config, config_string);
|
||||
config_string = config_string.substring(0,config_string.length()-1);
|
||||
|
||||
return EDK_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function to create a bme68x label information file with .bmelabelinfo extension
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::create_label_info_file()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
String mac_str = utils::get_mac_address();
|
||||
String label_file_base_name = "_Board_" + mac_str + "_PowerOnOff_1_";
|
||||
uint16_t label_tag = 1001; //since labelTag starts with 1001
|
||||
|
||||
_label_file_name = utils::get_date_time() + label_file_base_name + utils::get_file_seed() +
|
||||
"_File_" + String(_bsec_file_counter) + BME68X_LABEL_INFO_FILE_EXT;
|
||||
File logFile;
|
||||
|
||||
if (!logFile.open(_label_file_name.c_str(), O_RDWR | O_CREAT))
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LABEL_INFO_FILE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
filter2.clear();
|
||||
label_doc.clear();
|
||||
|
||||
/* write labelinfo header / skeleton */
|
||||
logFile.println("{");
|
||||
logFile.println("\t\"labelInfoHeader\": {");
|
||||
logFile.println("\t\t\"counterPowerOnOff\": 1,");
|
||||
logFile.println("\t\t\"seedPowerOnOff\": \"" + utils::get_file_seed() + "\",");
|
||||
logFile.println("\t\t\"dateCreated\": \"" + String(utils::get_rtc().now().unixtime()) + "\",");
|
||||
logFile.println("\t\t\"dateCreated_ISO\": \"" + utils::get_rtc().now().timestamp() + "+00:00\",");
|
||||
logFile.println("\t\t\"firmwareVersion\": \"" + String(FIRMWARE_VERSION) + "\",");
|
||||
logFile.println("\t\t\"boardId\": \"" + mac_str + "\"");
|
||||
logFile.println("\t},");
|
||||
logFile.println("\t\"labelInformation\": [");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 0,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Initial\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for no label has been set\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 1,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 1\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 1 pressed\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 2,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 2\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 2 pressed\"");
|
||||
logFile.println("\t\t},");
|
||||
logFile.println("\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": 3,");
|
||||
logFile.println("\t\t\t\"labelName\": \"Button 1+2\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Standard label for hardware button 1 and button 2 pressed\"");
|
||||
logFile.print("\t\t}");
|
||||
|
||||
filter2["aiConfigBody"]["type"] = true;
|
||||
filter2["aiConfigBody"]["classes"] = true;
|
||||
filter2["aiConfigBody"]["targets"] = true;
|
||||
|
||||
File configFile;
|
||||
configFile.open(_ai_config_name.c_str(), O_RDWR);
|
||||
|
||||
DeserializationError error = deserializeJson(label_doc, configFile, DeserializationOption::Filter(filter2));
|
||||
configFile.close();
|
||||
|
||||
if (error)
|
||||
{
|
||||
Serial.println(error.c_str());
|
||||
return EDK_SENSOR_MANAGER_JSON_DESERIAL_ERROR;
|
||||
}
|
||||
|
||||
// reading configuration type
|
||||
const char* type = label_doc["aiConfigBody"]["type"];
|
||||
|
||||
strcpy(ai_config_type, type);
|
||||
|
||||
if (strcmp(type, "classification") == 0)
|
||||
{
|
||||
|
||||
for (JsonObject classes : label_doc["aiConfigBody"]["classes"].as<JsonArray>())
|
||||
{
|
||||
const char* class_name = classes["name"];
|
||||
|
||||
logFile.println(",\n\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": " + String(label_tag++) + ",");
|
||||
logFile.println("\t\t\t\"labelName\": \"" + String(class_name) + "\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Predefined by algorithm classes (class name used as labelName)\"");
|
||||
logFile.print("\t\t}");
|
||||
}
|
||||
}
|
||||
else if (strcmp(type, "regression") == 0)
|
||||
{
|
||||
|
||||
for (JsonObject target_name : label_doc["aiConfigBody"]["targets"].as<JsonArray>())
|
||||
{
|
||||
const char* targets = target_name["name"];
|
||||
|
||||
logFile.println(",\n\t\t{");
|
||||
logFile.println("\t\t\t\"labelTag\": " + String(label_tag++) + ",");
|
||||
logFile.println("\t\t\t\"labelName\": \"" + String(targets) + "\",");
|
||||
logFile.println("\t\t\t\"labelDescription\": \"Predefined by algorithm Targets (target name used as labelName)\"");
|
||||
logFile.print("\t\t}");
|
||||
}
|
||||
}
|
||||
logFile.println("\n\t]");
|
||||
logFile.print("}");
|
||||
|
||||
/* close log file */
|
||||
logFile.close();
|
||||
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Function which flushes the buffered sensor data to the current log file
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::flush_sensor_data(uint8_t sensor_num)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
File logFile;
|
||||
std::string txt;
|
||||
|
||||
if (_bs.rdbuf()->in_avail())
|
||||
{
|
||||
txt = _bs.str();
|
||||
_bs.str(std::string());
|
||||
|
||||
if (_bme_file_counter && logFile.open(_bme_file_name.c_str(), O_RDWR | O_AT_END))
|
||||
{
|
||||
logFile.seek(_bme_data_pos);
|
||||
logFile.print(txt.c_str());
|
||||
_bme_data_pos = logFile.position();
|
||||
logFile.print("\n\t\t]\n\t}\n}");
|
||||
|
||||
if (logFile.size() >= FILE_SIZE_LIMIT)
|
||||
{
|
||||
logFile.close();
|
||||
++_bme_file_counter;
|
||||
ret_code = create_raw_data_file(sensor_num);
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
ret_code = create_label_info_file();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function writes the bsec output to the current log file
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::write_bsec_output(sensor_io_data& buff_data)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
File logFile;
|
||||
|
||||
if (_bsec_file_counter && logFile.open(_ai_file_name.c_str(), O_RDWR | O_AT_END))
|
||||
{
|
||||
/* set writing position to end of data block */
|
||||
logFile.seek(_ai_data_pos);
|
||||
|
||||
float gas_signal[4] = {NAN, NAN, NAN, NAN}, iaq_signal = NAN;
|
||||
uint8_t iaq_accuracy = 0xFF; //, gasAccuracy = 0xFF;
|
||||
uint8_t gas_accuracy[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint8_t is_reg_class_subscribe = 0;
|
||||
uint8_t Gas_accuracy = 0;
|
||||
uint8_t index = 0;
|
||||
|
||||
for (uint8_t i = 0; ((buff_data.outputs).output != nullptr) && (i < (buff_data.outputs).nOutputs); i++)
|
||||
{
|
||||
const bsec_output_t& output = (buff_data.outputs).output[i];
|
||||
|
||||
if (output.sensor_id >= BSEC_OUTPUT_GAS_ESTIMATE_1 && output.sensor_id <= BSEC_OUTPUT_GAS_ESTIMATE_4)
|
||||
{
|
||||
index = output.sensor_id - BSEC_OUTPUT_GAS_ESTIMATE_1;
|
||||
gas_signal[index] = output.signal;
|
||||
gas_accuracy[index] = (output.accuracy > gas_accuracy[index]) ? gas_accuracy[index] : output.accuracy;
|
||||
Gas_accuracy |= ((gas_accuracy[index] & 0x03) << (index * 2));
|
||||
is_reg_class_subscribe = 1;
|
||||
}
|
||||
else if (output.sensor_id >= BSEC_OUTPUT_REGRESSION_ESTIMATE_1 && output.sensor_id <= BSEC_OUTPUT_REGRESSION_ESTIMATE_4)
|
||||
{
|
||||
index = output.sensor_id - BSEC_OUTPUT_REGRESSION_ESTIMATE_1;
|
||||
gas_signal[index] = output.signal;
|
||||
gas_accuracy[index] = (output.accuracy > gas_accuracy[index]) ? gas_accuracy[index] : output.accuracy;
|
||||
Gas_accuracy |= ((gas_accuracy[index] & 0x03) << (index * 2));
|
||||
is_reg_class_subscribe = 1;
|
||||
}
|
||||
else if(output.sensor_id == BSEC_OUTPUT_IAQ)
|
||||
{
|
||||
iaq_signal = output.signal;
|
||||
iaq_accuracy = output.accuracy;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_first_line)
|
||||
{
|
||||
logFile.println(",");
|
||||
}
|
||||
logFile.print("\t\t\t[\n\t\t\t\t");
|
||||
logFile.print(buff_data.sensor_num);
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
logFile.print(buff_data.sensor_id);
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
logFile.print(buff_data.start_time_since_power_on);
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
logFile.print(buff_data.end_time_since_power_on);
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(!isnan(gas_signal[0])) ? logFile.print(gas_signal[0]) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(!isnan(gas_signal[1])) ? logFile.print(gas_signal[1]) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(!isnan(gas_signal[2])) ? logFile.print(gas_signal[2]) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(!isnan(gas_signal[3])) ? logFile.print(gas_signal[3]) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(is_reg_class_subscribe == 1) ? logFile.print(Gas_accuracy) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(!isnan(iaq_signal)) ? logFile.print(iaq_signal) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
(iaq_accuracy != 0xFF) ? logFile.print(iaq_accuracy) : logFile.print("null");
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
logFile.print(buff_data.code);
|
||||
logFile.print(",\n\t\t\t\t");
|
||||
logFile.println(buff_data.ground_truth);
|
||||
logFile.print("\t\t\t]");
|
||||
|
||||
_ai_data_pos = logFile.position();
|
||||
_first_line = false;
|
||||
logFile.println("\n\t\t]\n\t}\n}");
|
||||
|
||||
logFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_LOG_FILE_ERROR;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function writes the sensor data to the current log file.
|
||||
*/
|
||||
demo_ret_code bsecDataLogger::write_sensor_data(const uint8_t* num, const uint32_t* sensor_id,
|
||||
const bme68x_data* bme68xData, const uint32_t* scan_cycle_index,
|
||||
uint32_t ground_truth, demo_ret_code code, sensor_io_data& buff_data)
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
uint32_t rtc_tsp = utils::get_rtc().now().unixtime();
|
||||
uint32_t time_since_power_on = millis();
|
||||
|
||||
//Copying time for sync with aiprediction file
|
||||
if (bme68xData != nullptr)
|
||||
{
|
||||
|
||||
if (bme68xData->gas_index == 0)
|
||||
{
|
||||
buff_data.start_time_since_power_on = time_since_power_on;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff_data.end_time_since_power_on = time_since_power_on;
|
||||
}
|
||||
}
|
||||
|
||||
if (_end_of_line)
|
||||
{
|
||||
_bs << ",\n";
|
||||
}
|
||||
_bs << "\t\t\t[\n\t\t\t\t";
|
||||
(num != nullptr) ? (_bs << (int32_t)*num) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(sensor_id != nullptr) ? (_bs << (int32_t)*sensor_id) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
_bs << time_since_power_on;
|
||||
_bs << ",\n\t\t\t\t";
|
||||
_bs << rtc_tsp;
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_bs << bme68xData->temperature) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_bs << bme68xData->pressure) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_bs << bme68xData->humidity) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_bs << bme68xData->gas_resistance) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(bme68xData != nullptr) ? (_bs << (int32_t)bme68xData->gas_index) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
_bs << (bool)(BME68X_PARALLEL_MODE);
|
||||
_bs << ",\n\t\t\t\t";
|
||||
(scan_cycle_index != nullptr) ? (_bs << (int32_t)(*scan_cycle_index)) : (_bs << "null");
|
||||
_bs << ",\n\t\t\t\t";
|
||||
_bs << ground_truth;
|
||||
_bs << ",\n\t\t\t\t";
|
||||
_bs << (int32_t)code;
|
||||
_bs << "\n\t\t\t]";
|
||||
|
||||
_end_of_line = true;
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
195
libraries/bsec2/examples/bme68x_demo_sample/bsec_datalogger.h
Normal file
195
libraries/bsec2/examples/bme68x_demo_sample/bsec_datalogger.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bsec_datalogger.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the bsec datalogger
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSEC_DATALOGGER_H
|
||||
#define BSEC_DATALOGGER_H
|
||||
|
||||
/* Include of Arduino Core */
|
||||
#include "Arduino.h"
|
||||
#include <SdFat.h>
|
||||
#include <RTClib.h>
|
||||
#include <base64.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "utils.h"
|
||||
#include "demo_app.h"
|
||||
#include "label_provider.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
/* Number of sensors to operate*/
|
||||
#define NUM_OF_SENS UINT8_C(4)
|
||||
#define COUNT_MAX_SIZE UINT8_C(2)
|
||||
|
||||
/*!
|
||||
* @brief Class library that holds functionality of the bsec datalogger
|
||||
*/
|
||||
class bsecDataLogger
|
||||
{
|
||||
private:
|
||||
String _ai_config_name, _ai_file_name, _bme_file_name, _label_file_name;
|
||||
std::stringstream _bs, _ba;
|
||||
uint32_t _ai_data_pos = 0, _bme_data_pos = 0;
|
||||
uint32_t _bme_file_counter = 1;
|
||||
uint32_t _bsec_file_counter = 1;
|
||||
bool _first_line = false;
|
||||
bsec_version_t _version;
|
||||
bool _end_of_line = false;
|
||||
String config_string;
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a bsec output file
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code create_bsec_file();
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a bme68x datalogger output file
|
||||
*
|
||||
* @param[in] sensorNum : Selected sensor number
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code create_raw_data_file(uint8_t sensor_num);
|
||||
|
||||
/*!
|
||||
* @brief : Fuction that parses the config data from aiConfig file and creates config header and body
|
||||
*
|
||||
* @param[in] sensorNum : Selected sensor number
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code prepare_config_content(uint8_t sensor_num);
|
||||
|
||||
public:
|
||||
/*!
|
||||
* @brief structure which comprises sensor input and output data to write into SD card
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/*! sensor number */
|
||||
uint8_t sensor_num;
|
||||
|
||||
/*! sensor Index */
|
||||
uint32_t sensor_id;
|
||||
|
||||
/*! bsec output structure*/
|
||||
bsecOutputs outputs;
|
||||
|
||||
/*! return code */
|
||||
demo_ret_code code;
|
||||
|
||||
/*! start time since power on */
|
||||
uint32_t start_time_since_power_on;
|
||||
|
||||
/*! end time since power on */
|
||||
uint32_t end_time_since_power_on;
|
||||
|
||||
/*! ground truth */
|
||||
uint16_t ground_truth;
|
||||
|
||||
} sensor_io_data;
|
||||
|
||||
uint8_t scanCycles = 0;
|
||||
|
||||
/* Holds the aiconfig type (clasification / regression) */
|
||||
char ai_config_type[15] = {};
|
||||
|
||||
/*!
|
||||
* @brief :The constructor of the bsec_datalogger class
|
||||
* Creates an instance of the class
|
||||
*/
|
||||
bsecDataLogger();
|
||||
|
||||
/*!
|
||||
* @brief : This function configures the bsec datalogger using the provided bsec config string file.
|
||||
*
|
||||
* @param[in] configName : sensor configuration file
|
||||
* @param[in] bsecVersion : reference to bsec version
|
||||
* @param[in] sensorNum : selected sensor number
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code begin(const String& config_name, const bsec_version_t& bsec_version, uint8_t sensor_num);
|
||||
|
||||
/*!
|
||||
* @brief : This function flushes the buffered sensor data to the current log file
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code flush_sensor_data(uint8_t sensor_num);
|
||||
|
||||
/*!
|
||||
* @brief : This function writes the bsec output to the current log file.
|
||||
*
|
||||
* @param[in] buffData : reference to the buffered data
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
|
||||
demo_ret_code write_bsec_output(sensor_io_data& buff_data);
|
||||
|
||||
/*!
|
||||
* @brief : This function writes the sensor data to the current log file.
|
||||
*
|
||||
* @param[in] num : sensor number
|
||||
* @param[in] sensorId : pointer to sensor id, if NULL a null json object is inserted
|
||||
* @param[in] sensorMode : pointer to sensor operation mode, if NULL a null json object is inserted
|
||||
* @param[in] bme68xData : pointer to bme68x data, if NULL a null json object is inserted
|
||||
* @param[in] scanCycleIndex : pointer to sensor scanning cycle index
|
||||
* @param[in] label : class label
|
||||
* @param[in] code : application return code
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code write_sensor_data(const uint8_t* num, const uint32_t* sensor_id, const bme68x_data* bme68xData,
|
||||
const uint32_t* scan_cycle_index, uint32_t ground_truth, demo_ret_code code,
|
||||
sensor_io_data& buff_data);
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a bme68x label information file with .bmelabelinfo extension
|
||||
*
|
||||
* @return bosch error code
|
||||
*/
|
||||
demo_ret_code create_label_info_file();
|
||||
};
|
||||
|
||||
#endif
|
||||
137
libraries/bsec2/examples/bme68x_demo_sample/demo_app.h
Normal file
137
libraries/bsec2/examples/bme68x_demo_sample/demo_app.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file demo_app.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the bosch application definitions
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DEMO_APPLICATION_H
|
||||
#define DEMO_APPLICATION_H
|
||||
|
||||
#include "bsec2.h"
|
||||
|
||||
#define FIRMWARE_VERSION "2.1.5"
|
||||
|
||||
/*!
|
||||
* @brief Enumeration for demo app mode
|
||||
*/
|
||||
enum demo_app_mode
|
||||
{
|
||||
DEMO_RECORDING_MODE,
|
||||
DEMO_TEST_ALGORITHM_MODE,
|
||||
DEMO_IDLE_MODE
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Enumeration for the demo app return code
|
||||
*/
|
||||
enum demo_ret_code
|
||||
{
|
||||
EDK_LABEL_NOT_FOUND = -28,
|
||||
EDK_DATALOGGER_LABEL_INFO_FILE_ERROR = -27,
|
||||
EDK_DATALOGGER_AI_CONFIG_FILE_ERROR = -26,
|
||||
EDK_SENSOR_INITIALIZATION_FAILED = -25,
|
||||
EDK_EXTENSION_NOT_AVAILABLE = -24,
|
||||
EDK_END_OF_FILE = -23,
|
||||
EDK_FILE_OPEN_ERROR = -22,
|
||||
EDK_BUFFER_DATA_ERROR = -21,
|
||||
EDK_BLE_CONTROLLER_FULL_QUEUE = -20,
|
||||
EDK_BLE_CONTROLLER_INVALID_CMD = -19,
|
||||
EDK_BLE_CONTROLLER_OUT_OF_RANGE = -18,
|
||||
EDK_BLE_CONTROLLER_OUT_OF_BOUNDS = -17,
|
||||
|
||||
EDK_BSEC_INIT_ERROR = -16,
|
||||
EDK_BSEC_SET_CONFIG_ERROR = -15,
|
||||
EDK_BSEC_UPDATE_SUBSCRIPTION_ERROR = -14,
|
||||
EDK_BSEC_RUN_ERROR = -13,
|
||||
|
||||
EDK_DATALOGGER_LOG_FILE_ERROR = -12,
|
||||
EDK_DATALOGGER_SENSOR_CONFIG_FILE_ERROR = -11,
|
||||
|
||||
EDK_BME68X_DRIVER_ERROR = -10,
|
||||
|
||||
EDK_SENSOR_MANAGER_CONFIG_FILE_ERROR = -9,
|
||||
EDK_SENSOR_MANAGER_SENSOR_INDEX_ERROR = -8,
|
||||
EDK_SENSOR_MANAGER_JSON_DESERIAL_ERROR = -7,
|
||||
EDK_SENSOR_MANAGER_JSON_FORMAT_ERROR = -6,
|
||||
|
||||
EDK_BSEC_CONFIG_STR_FILE_ERROR = -5,
|
||||
EDK_BSEC_CONFIG_STR_READ_ERROR = -4,
|
||||
EDK_BSEC_CONFIG_STR_SIZE_ERROR = -3,
|
||||
|
||||
EDK_SD_CARD_INIT_ERROR = -2,
|
||||
EDK_SENSOR_CONFIG_MISSING_ERROR = -1,
|
||||
|
||||
EDK_OK = 0,
|
||||
|
||||
EDK_SENSOR_MANAGER_DATA_MISS_WARNING = 1,
|
||||
|
||||
EDK_DATALOGGER_RTC_BEGIN_WARNING = 2,
|
||||
EDK_DATALOGGER_RTC_ADJUST_WARNING = 3
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Structure to hold heater profile data
|
||||
*/
|
||||
struct bme68x_heater_profile
|
||||
{
|
||||
uint64_t sleep_duration;
|
||||
uint16_t temperature[10];
|
||||
uint16_t duration[10];
|
||||
uint8_t nb_repetitions;
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Structure to hold sensor state information
|
||||
*/
|
||||
struct bme68x_sensor
|
||||
{
|
||||
bme68xDev device;
|
||||
bme68x_heater_profile heater_profile;
|
||||
|
||||
uint64_t wake_up_time;
|
||||
uint32_t id;
|
||||
bool is_configured;
|
||||
uint8_t mode;
|
||||
uint8_t cycle_pos;
|
||||
uint8_t next_gas_index;
|
||||
int8_t i2c_mask;
|
||||
uint32_t scan_cycle_index;
|
||||
};
|
||||
|
||||
#endif
|
||||
144
libraries/bsec2/examples/bme68x_demo_sample/label_provider.cpp
Normal file
144
libraries/bsec2/examples/bme68x_demo_sample/label_provider.cpp
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file label_provider.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief label provider
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "label_provider.h"
|
||||
|
||||
volatile gas_label labelProvider::_label;
|
||||
volatile bool labelProvider::_but1_pressed, labelProvider::_but2_pressed;
|
||||
|
||||
QueueHandle_t labelProvider::_queue = nullptr;
|
||||
|
||||
/*!
|
||||
* @brief The constructor of the label_provider class
|
||||
*/
|
||||
labelProvider::labelProvider()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* @brief This function initializes the label provider module
|
||||
*/
|
||||
void labelProvider::begin()
|
||||
{
|
||||
_but1_pressed = false;
|
||||
_but2_pressed = false;
|
||||
|
||||
_queue = xQueueCreate(2, sizeof(gas_label));
|
||||
|
||||
/* Button interrupts setup and attachment */
|
||||
pinMode(PIN_BUTTON_1, INPUT_PULLUP);
|
||||
pinMode(PIN_BUTTON_2, INPUT_PULLUP);
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON_1), isr_button1, CHANGE);
|
||||
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON_2), isr_button2, CHANGE);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function is the interrupt function, that handles the button press of the first button
|
||||
*/
|
||||
void labelProvider::isr_button1()
|
||||
{
|
||||
/* check if button is pressed or idle */
|
||||
if (_but1_pressed == false)
|
||||
{
|
||||
/* determine if only this button or both are pressed and set helper button label */
|
||||
_but1_pressed = true;
|
||||
|
||||
if (_but2_pressed)
|
||||
{
|
||||
_label = BSEC_CLASS_3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_label = BSEC_CLASS_1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if both buttons are released, user label according to helper button label */
|
||||
_but1_pressed = false;
|
||||
|
||||
if (!_but2_pressed)
|
||||
{
|
||||
xQueueSendFromISR(_queue, (const void*)&_label, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function is the interrupt function, that handles the button press of the second button
|
||||
*/
|
||||
void labelProvider::isr_button2()
|
||||
{
|
||||
/* check if button is pressed or idle */
|
||||
if (_but2_pressed == false)
|
||||
{
|
||||
/* determine if only this button or both are pressed and set helper button label */
|
||||
_but2_pressed = true;
|
||||
|
||||
if (_but1_pressed)
|
||||
{
|
||||
_label = BSEC_CLASS_3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_label = BSEC_CLASS_2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if both buttons are released, user label according to helper button label */
|
||||
_but2_pressed = false;
|
||||
|
||||
if (!_but1_pressed)
|
||||
{
|
||||
xQueueSendFromISR(_queue, (const void*)&_label, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the current label
|
||||
*/
|
||||
bool labelProvider::get_label(gas_label &label)
|
||||
{
|
||||
return xQueueReceive(_queue, &label, 0);
|
||||
}
|
||||
113
libraries/bsec2/examples/bme68x_demo_sample/label_provider.h
Normal file
113
libraries/bsec2/examples/bme68x_demo_sample/label_provider.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file label_provider.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the label provider
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LABEL_PROVIDER_H
|
||||
#define LABEL_PROVIDER_H
|
||||
|
||||
/* Include of Arduino Core */
|
||||
#include "Arduino.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
/* Pins connected to interrupt buttons */
|
||||
#define PIN_BUTTON_1 UINT8_C(32)
|
||||
#define PIN_BUTTON_2 UINT8_C(14)
|
||||
#define LABEL_NAME_SIZE UINT8_C(50)
|
||||
#define LABEL_DESC_SIZE UINT8_C(200)
|
||||
#define LABEL_TAG_MAX_RANGE UINT32_C(2147483647)
|
||||
#define LABEL_TAG_MIN_RANGE UINT16_C(1001)
|
||||
|
||||
enum gas_label
|
||||
{
|
||||
BSEC_NO_CLASS,
|
||||
BSEC_CLASS_1,
|
||||
BSEC_CLASS_2,
|
||||
BSEC_CLASS_3,
|
||||
BSEC_CLASS_4
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief : Class library that holds functionality of the label provider
|
||||
*/
|
||||
class labelProvider
|
||||
{
|
||||
private:
|
||||
/* variable for temporarily holding the new set user label */
|
||||
static volatile gas_label _label;
|
||||
/* variables to store information about the current buttons states */
|
||||
static volatile bool _but1_pressed, _but2_pressed;
|
||||
|
||||
static QueueHandle_t _queue;
|
||||
|
||||
/*!
|
||||
* @brief : This function is the interrupt handler of the first button
|
||||
*/
|
||||
static void isr_button1();
|
||||
|
||||
/*!
|
||||
* @brief : This function is the interrupt handler of the second button
|
||||
*/
|
||||
static void isr_button2();
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* @brief : The constructor of the label_provider class
|
||||
* Creates an instance of the class
|
||||
*/
|
||||
labelProvider();
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes the label provider module
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the current label.
|
||||
*
|
||||
* @param[out] label : reference to the label
|
||||
*
|
||||
* @return true if a new label is available else false
|
||||
*/
|
||||
bool get_label(gas_label &label);
|
||||
};
|
||||
|
||||
#endif
|
||||
110
libraries/bsec2/examples/bme68x_demo_sample/led_controller.cpp
Normal file
110
libraries/bsec2/examples/bme68x_demo_sample/led_controller.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file led_controller.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief led controller
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "led_controller.h"
|
||||
|
||||
/*!
|
||||
* @brief The constructor of the led_controller class
|
||||
*/
|
||||
ledController::ledController()
|
||||
{
|
||||
previous_ret_code = EDK_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function initializes the led controller module
|
||||
*/
|
||||
void ledController::begin()
|
||||
{
|
||||
/* LED pin initialization for runtime monitoring and error indication */
|
||||
pinMode(PIN_LED, OUTPUT);
|
||||
digitalWrite(PIN_LED, LOW);
|
||||
|
||||
_led_on = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function updates the led blinking pattern according to the
|
||||
* provided period
|
||||
*/
|
||||
void ledController::switch_led(uint32_t period)
|
||||
{
|
||||
uint32_t time_stamp = millis();
|
||||
|
||||
if ((time_stamp - _time_stamp) >= period)
|
||||
{
|
||||
|
||||
if (_led_on)
|
||||
{
|
||||
digitalWrite(PIN_LED, LOW);
|
||||
_led_on = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(PIN_LED, HIGH);
|
||||
_led_on = true;
|
||||
}
|
||||
_time_stamp = time_stamp;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function updates the led controller status
|
||||
*/
|
||||
void ledController::update(demo_ret_code retcode)
|
||||
{
|
||||
|
||||
if (retcode >= EDK_OK)
|
||||
{
|
||||
switch_led(LED_OK_PERIOD);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (retcode != previous_ret_code)
|
||||
{
|
||||
Serial.println("Error code = " + String((int32_t) retcode));
|
||||
previous_ret_code = retcode;
|
||||
}
|
||||
switch_led(LED_ERROR_PERIOD);
|
||||
}
|
||||
}
|
||||
95
libraries/bsec2/examples/bme68x_demo_sample/led_controller.h
Normal file
95
libraries/bsec2/examples/bme68x_demo_sample/led_controller.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file led_controller.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the led_controller
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LED_CONTROLLER_H
|
||||
#define LED_CONTROLLER_H
|
||||
|
||||
/* Include of Arduino Core */
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "demo_app.h"
|
||||
|
||||
#define PIN_LED UINT8_C(13)
|
||||
#define LED_ERROR_PERIOD UINT8_C(100)
|
||||
#define LED_OK_PERIOD UINT16_C(1000)
|
||||
|
||||
/*!
|
||||
* @brief : Class library that holds functionality of the led controller
|
||||
*/
|
||||
class ledController
|
||||
{
|
||||
private:
|
||||
bool _led_on = false;
|
||||
uint32_t _time_stamp = 0;
|
||||
demo_ret_code previous_ret_code;
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the led blinking pattern according to
|
||||
* the provided period.
|
||||
*
|
||||
* @param[in] period : blinking period
|
||||
*/
|
||||
void switch_led(uint32_t period);
|
||||
|
||||
public:
|
||||
/*!
|
||||
* @brief : The constructor of the led_controller class
|
||||
* Creates an instance of the class
|
||||
*/
|
||||
ledController();
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes the led controller module
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/*!
|
||||
* @brief : This function updates the led controller status. It should be
|
||||
* called at least 10 times per second to ensure that the correct
|
||||
* blinking pattern is generated.
|
||||
*
|
||||
* @param[in] retCode : error code
|
||||
*/
|
||||
void update(demo_ret_code ret_code);
|
||||
};
|
||||
|
||||
#endif
|
||||
354
libraries/bsec2/examples/bme68x_demo_sample/sensor_manager.cpp
Normal file
354
libraries/bsec2/examples/bme68x_demo_sample/sensor_manager.cpp
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file sensor_manager.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief sensor manager
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* own header include */
|
||||
#include "sensor_manager.h"
|
||||
|
||||
bme68x_sensor sensorManager::_sensors[NUM_BME68X_UNITS];
|
||||
comm_mux comm_setup[NUM_BME68X_UNITS];
|
||||
|
||||
/*!
|
||||
* @brief The constructor of the sensorManager class
|
||||
*/
|
||||
sensorManager::sensorManager()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* @brief This function initializes the given BME688 sensor
|
||||
*/
|
||||
int8_t sensorManager::initialize_sensor(uint8_t sensor_number, uint32_t& sensor_id)
|
||||
{
|
||||
int8_t bme68x_rslt;
|
||||
|
||||
bme68xSensors[sensor_number].begin(BME68X_SPI_INTF, comm_mux_read, comm_mux_write, comm_mux_delay,
|
||||
&comm_setup[sensor_number]);
|
||||
bme68x_rslt = bme68xSensors[sensor_number].status;
|
||||
|
||||
if (bme68x_rslt != BME68X_OK)
|
||||
{
|
||||
return bme68x_rslt;
|
||||
}
|
||||
sensor_id = bme68xSensors[sensor_number].getUniqueId();
|
||||
bme68x_rslt = bme68xSensors[sensor_number].status;
|
||||
return bme68x_rslt;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function configures the heater settings of the sensor
|
||||
*/
|
||||
int8_t sensorManager::set_heater_profile(const String& heater_profile_str, const String& duty_cycle_str,
|
||||
bme68x_heater_profile& heater_profile, uint8_t sensor_number)
|
||||
{
|
||||
/* get heater profiles from parsed object */
|
||||
JsonArray heaterProfilesJson = _configDoc["configBody"]["heaterProfiles"].as<JsonArray>();
|
||||
|
||||
/* iterate over all heater profiles */
|
||||
for (JsonVariant _heaterProfileJson: heaterProfilesJson)
|
||||
{
|
||||
|
||||
/* compare with profile of given sensor */
|
||||
if (heater_profile_str == _heaterProfileJson["id"].as<String>())
|
||||
{
|
||||
/* on match, save heater temperature and duration vectors */
|
||||
heater_profile.length = _heaterProfileJson["temperatureTimeVectors"].size();
|
||||
|
||||
for (uint32_t i = 0; i < heater_profile.length; i++)
|
||||
{
|
||||
heater_profile.temperature[i] = _heaterProfileJson["temperatureTimeVectors"][i][0].as<uint16_t>();
|
||||
heater_profile.duration[i] = _heaterProfileJson["temperatureTimeVectors"][i][1].as<uint16_t>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* get duty cycle profiles from parsed object */
|
||||
JsonArray dutyCycleProfilesJson = _configDoc["configBody"]["dutyCycleProfiles"].as<JsonArray>();
|
||||
|
||||
/* iterate over all duty cycle profiles */
|
||||
for (JsonVariant _dutyCycleProfileJson : dutyCycleProfilesJson)
|
||||
{
|
||||
/* compare with profile of the given sensor */
|
||||
if (duty_cycle_str == _dutyCycleProfileJson["id"].as<String>())
|
||||
{
|
||||
/* on match, save duty cycle information to the sensor profile */
|
||||
heater_profile.nb_repetitions = _dutyCycleProfileJson["numberScanningCycles"].as<uint8_t>();
|
||||
heater_profile.sleep_duration = _dutyCycleProfileJson["numberSleepingCycles"].as<uint8_t>();
|
||||
|
||||
uint64_t sleep_duration = 0;
|
||||
|
||||
for (uint16_t dur : heater_profile.duration)
|
||||
{
|
||||
sleep_duration += (uint64_t)dur * HEATER_TIME_BASE;
|
||||
}
|
||||
heater_profile.sleep_duration *= sleep_duration;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return configure_sensor(heater_profile, sensor_number);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function configures the bme688 sensor
|
||||
*/
|
||||
int8_t sensorManager::configure_sensor(bme68x_heater_profile& heater_profile, uint8_t sensor_number)
|
||||
{
|
||||
bme68xSensors[sensor_number].setTPH();
|
||||
int8_t bme68x_rslt = bme68xSensors[sensor_number].status;
|
||||
|
||||
if (bme68x_rslt != BME68X_OK)
|
||||
{
|
||||
return bme68x_rslt;
|
||||
}
|
||||
|
||||
/* getMeasDur() returns Measurement duration in micro sec. to convert to milli sec. '/ INT64_C(1000)' */
|
||||
uint32_t shared_heatr_dur = HEATER_TIME_BASE -
|
||||
(bme68xSensors[sensor_number].getMeasDur(BME68X_PARALLEL_MODE) / INT64_C(1000));
|
||||
/* sets the heater configuration of the sensor */
|
||||
bme68xSensors[sensor_number].setHeaterProf(heater_profile.temperature, heater_profile.duration,
|
||||
shared_heatr_dur, heater_profile.length);
|
||||
return bme68xSensors[sensor_number].status;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function initializes all bme688 sensors
|
||||
*/
|
||||
demo_ret_code sensorManager::initialize_all_sensors()
|
||||
{
|
||||
int8_t bme68x_rslt = BME68X_OK;
|
||||
comm_mux_begin(Wire, SPI);
|
||||
|
||||
for (uint8_t i = 0; i < NUM_BME68X_UNITS; i++)
|
||||
{
|
||||
bme68x_sensor* sensor = get_sensor(i);
|
||||
/* Communication interface set for all the 8 sensors */
|
||||
comm_setup[i] = comm_mux_set_config(Wire, SPI, i, comm_setup[i]);
|
||||
|
||||
if (sensor != nullptr)
|
||||
{
|
||||
sensor->i2c_mask = ((0x01 << i) ^ 0xFF);//TODO
|
||||
bme68x_rslt = initialize_sensor(i, sensor->id);
|
||||
|
||||
if (bme68x_rslt != BME68X_OK)
|
||||
{
|
||||
return EDK_BME68X_DRIVER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EDK_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function configures the sensor manager using the provided config file
|
||||
*/
|
||||
demo_ret_code sensorManager::begin(const String& config_name)
|
||||
{
|
||||
int8_t bme68xRslt = BME68X_OK;
|
||||
|
||||
comm_mux_begin(Wire, SPI);
|
||||
|
||||
/* Communication interface set for all the 8 sensors in the development kit */
|
||||
for (uint8_t i = 0; i < NUM_BME68X_UNITS; i++)
|
||||
{
|
||||
comm_setup[i] = comm_mux_set_config(Wire, SPI, i, comm_setup[i]);
|
||||
}
|
||||
|
||||
/* open config file */
|
||||
File configFile;
|
||||
|
||||
if (configFile.open(config_name.c_str(), O_READ))
|
||||
{
|
||||
/* read in configuration and parse to JSON object */
|
||||
DeserializationError error = deserializeJson(_configDoc, configFile);
|
||||
/* close config file */
|
||||
configFile.close();
|
||||
|
||||
if (error)
|
||||
{
|
||||
Serial.println(error.c_str());
|
||||
return EDK_SENSOR_MANAGER_JSON_DESERIAL_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return EDK_SENSOR_MANAGER_CONFIG_FILE_ERROR;
|
||||
}
|
||||
|
||||
memset(_sensors, 0, sizeof(_sensors));
|
||||
|
||||
JsonArray devicefigurations = _configDoc["configBody"]["sensorConfigurations"].as<JsonArray>();
|
||||
|
||||
for (JsonVariant devicefig : devicefigurations)
|
||||
{
|
||||
/* save config information to sensor profile */
|
||||
uint8_t sensor_number = devicefig["sensorIndex"].as<uint8_t>();
|
||||
bme68x_sensor* sensor = get_sensor(sensor_number);
|
||||
|
||||
if (sensor == nullptr)
|
||||
{
|
||||
return EDK_SENSOR_MANAGER_SENSOR_INDEX_ERROR;
|
||||
}
|
||||
|
||||
String heater_profile_str = devicefig["heaterProfile"].as<String>();
|
||||
String duty_cycle_str = devicefig["dutyCycleProfile"].as<String>();
|
||||
|
||||
sensor->is_configured = false;
|
||||
sensor->wake_up_time = 0;
|
||||
sensor->mode = BME68X_SLEEP_MODE;
|
||||
sensor->cycle_pos = 0;
|
||||
sensor->next_gas_index = 0;
|
||||
sensor->i2c_mask = ((0x01 << sensor_number) ^ 0xFF);
|
||||
sensor->scan_cycle_index = 1;
|
||||
|
||||
/* initialize the sensor */
|
||||
bme68xRslt = initialize_sensor(sensor_number, sensor->id);
|
||||
|
||||
if (bme68xRslt != BME68X_OK)
|
||||
{
|
||||
return EDK_BME68X_DRIVER_ERROR;
|
||||
}
|
||||
|
||||
/* set the heater profile */
|
||||
bme68xRslt = set_heater_profile(heater_profile_str, duty_cycle_str, sensor->heater_profile, sensor_number);
|
||||
|
||||
if (bme68xRslt != BME68X_OK)
|
||||
{
|
||||
return EDK_BME68X_DRIVER_ERROR;
|
||||
}
|
||||
|
||||
sensor->is_configured = true;
|
||||
}
|
||||
return EDK_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the selected sensor data
|
||||
*/
|
||||
demo_ret_code sensorManager::collect_data(uint8_t num, bme68x_data* data[3])
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
int8_t bme68x_rslt = BME68X_OK;
|
||||
|
||||
data[0] = data[1] = data[2] = nullptr;
|
||||
bme68x_sensor* sensor = get_sensor(num);
|
||||
|
||||
if (sensor == nullptr)
|
||||
{
|
||||
return EDK_SENSOR_MANAGER_SENSOR_INDEX_ERROR;
|
||||
}
|
||||
|
||||
uint64_t time_stamp = utils::get_tick_ms();
|
||||
|
||||
if (sensor->is_configured && (time_stamp >= sensor->wake_up_time))
|
||||
{
|
||||
|
||||
/* Wake up the sensor if necessary */
|
||||
if (sensor->mode == BME68X_SLEEP_MODE)
|
||||
{
|
||||
sensor->mode = BME68X_PARALLEL_MODE;
|
||||
bme68xSensors[num].setOpMode(BME68X_PARALLEL_MODE);
|
||||
bme68x_rslt = bme68xSensors[num].status;
|
||||
sensor->next_gas_index = 0;
|
||||
sensor->wake_up_time = time_stamp + GAS_WAIT_SHARED;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t nFields, j = 0;
|
||||
|
||||
nFields = bme68xSensors[num].fetchData();
|
||||
bme68x_data *sensor_data = bme68xSensors[num].getAllData();
|
||||
|
||||
for (uint8_t k = 0; k < 3; k++)
|
||||
{
|
||||
_field_data[k] = sensor_data[k];
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < nFields; i++)
|
||||
{
|
||||
|
||||
if (_field_data[i].status & BME68X_GASM_VALID_MSK)
|
||||
{
|
||||
uint8_t delta_index = _field_data[i].gas_index - sensor->next_gas_index;
|
||||
|
||||
if (delta_index > sensor->heater_profile.length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (delta_index > 0)
|
||||
{
|
||||
ret_code = EDK_SENSOR_MANAGER_DATA_MISS_WARNING;
|
||||
}
|
||||
|
||||
data[j++] = &_field_data[i];
|
||||
|
||||
sensor->next_gas_index = _field_data[i].gas_index + 1;
|
||||
|
||||
if (sensor->next_gas_index == sensor->heater_profile.length)
|
||||
{
|
||||
sensor->next_gas_index = 0;
|
||||
|
||||
if (++sensor->cycle_pos >= sensor->heater_profile.nb_repetitions)
|
||||
{
|
||||
sensor->cycle_pos = 0;
|
||||
sensor->mode = BME68X_SLEEP_MODE;
|
||||
sensor->wake_up_time = utils::get_tick_ms() + sensor->heater_profile.sleep_duration;
|
||||
bme68xSensors[num].setOpMode(BME68X_SLEEP_MODE);
|
||||
bme68x_rslt = bme68xSensors[num].status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sensor->wake_up_time = time_stamp + GAS_WAIT_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[0] == nullptr)
|
||||
{
|
||||
sensor->wake_up_time = time_stamp + GAS_WAIT_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
if (bme68x_rslt < BME68X_OK)
|
||||
{
|
||||
ret_code = EDK_BME68X_DRIVER_ERROR;
|
||||
}
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
207
libraries/bsec2/examples/bme68x_demo_sample/sensor_manager.h
Normal file
207
libraries/bsec2/examples/bme68x_demo_sample/sensor_manager.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file sensor_manager.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the sensor manager
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SENSOR_MANAGER_H
|
||||
#define SENSOR_MANAGER_H
|
||||
|
||||
/* Include of Arduino Core */
|
||||
#include <Arduino.h>
|
||||
#include <SdFat.h>
|
||||
#include <RTClib.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include "utils.h"
|
||||
#include "demo_app.h"
|
||||
#include <bme68xLibrary.h>
|
||||
#include <commMux\commMux.h>
|
||||
|
||||
/* I2C-Expander masks */
|
||||
#define I2C_EXPANDER_ADDR 0x20
|
||||
#define I2C_EXPANDER_OUTPUT_REG_ADDR 0x01
|
||||
#define I2C_EXPANDER_CONFIG_REG_ADDR 0x03
|
||||
#define I2C_EXPANDER_CONFIG_REG_MASK 0x00
|
||||
#define SPI_COMM_SPEED UINT32_C(4000000)
|
||||
#define NUM_BME68X_UNITS UINT8_C(8)
|
||||
#define HEATER_TIME_BASE UINT8_C(140)
|
||||
#define MAX_HEATER_DURATION UINT8_C(200)
|
||||
#define GAS_WAIT_SHARED UINT8_C(140)
|
||||
/* Size of Json document in bytes */
|
||||
#define JSON_DOC_SIZE UINT16_C(5000)
|
||||
|
||||
/*!
|
||||
* @brief : Class library that holds the functionality of the sensor manager
|
||||
*/
|
||||
class sensorManager
|
||||
{
|
||||
private:
|
||||
static bme68x_sensor _sensors[NUM_BME68X_UNITS];
|
||||
Bme68x bme68xSensors[NUM_BME68X_UNITS];
|
||||
bme68x_data _field_data[3];
|
||||
|
||||
StaticJsonDocument<JSON_DOC_SIZE> _configDoc;
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes the given BME688 sensor
|
||||
*
|
||||
* @param[in] sensorNumber : The sensor number
|
||||
* @param[in] sensorId : The sensor id
|
||||
*
|
||||
* @return 0 on success, lessthan zero otherwise
|
||||
*/
|
||||
int8_t initialize_sensor(uint8_t sensor_number, uint32_t& sensor_id);
|
||||
/*!
|
||||
* @brief : This function configures the heater settings of the sensor
|
||||
*
|
||||
* @param[in] heaterProfileStr : The heater profile string id
|
||||
* @param[in] dutyCycleStr : The duty cycle string id
|
||||
* @param[in] heaterProfile : The heater profile structure
|
||||
* @param[in] sensorNumber : The sensor number
|
||||
*
|
||||
* @return bme68x return code
|
||||
*/
|
||||
int8_t set_heater_profile(const String& heater_profile_str, const String& duty_cycle_str,
|
||||
bme68x_heater_profile& heater_profile, uint8_t sensor_number);
|
||||
|
||||
/*!
|
||||
* @brief : This function configures the bme688 sensor
|
||||
*
|
||||
* @param[in] heaterProfile : The heater profile structure
|
||||
* @param[in] sensorNumber : The sensor number
|
||||
*
|
||||
* @return bme68x return code
|
||||
*/
|
||||
int8_t configure_sensor(bme68x_heater_profile& heater_profile, uint8_t sensor_number);
|
||||
public:
|
||||
/*!
|
||||
* @brief : This function retrieves the selected sensor.
|
||||
*
|
||||
* @param[in] num : Sensor number
|
||||
*
|
||||
* @return Pointer to sensor if it exists, else nullptr
|
||||
*/
|
||||
static inline bme68x_sensor* get_sensor(uint8_t num)
|
||||
{
|
||||
bme68x_sensor* sensor = nullptr;
|
||||
|
||||
if (num < NUM_BME68X_UNITS)
|
||||
{
|
||||
sensor = &_sensors[num];
|
||||
}
|
||||
return sensor;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief : This function selects next readable bme688 sensor in given operation mode
|
||||
*
|
||||
* @param[inout] num : Reference to the sensor number
|
||||
* @param[in] mode : The sensor operation mode
|
||||
*
|
||||
* @return True if available
|
||||
*/
|
||||
static inline bool select_next_sensor(uint64_t& wake_up_time, uint8_t& num, uint8_t mode)
|
||||
{
|
||||
num = (uint8_t)0xFF;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_BME68X_UNITS; i++)
|
||||
{
|
||||
|
||||
if ((_sensors[i].mode == mode) && (_sensors[i].wake_up_time < wake_up_time))
|
||||
{
|
||||
wake_up_time = _sensors[i].wake_up_time;
|
||||
num = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (num < NUM_BME68X_UNITS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function schedules the next readable bme688 sensor
|
||||
*
|
||||
* @param[inout] num : Reference to the sensor number
|
||||
*
|
||||
* @return True if available
|
||||
*/
|
||||
static inline bool schedule_sensor(uint8_t& num)
|
||||
{
|
||||
uint64_t wake_up_time = utils::get_tick_ms() + 20;
|
||||
return (select_next_sensor(wake_up_time, num, BME68X_PARALLEL_MODE) ||
|
||||
select_next_sensor(wake_up_time, num, BME68X_SLEEP_MODE));
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief : The constructor of the sensorManager class
|
||||
* Creates an instance of the class
|
||||
*/
|
||||
sensorManager();
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes all bme688 sensors. It does not configure the sensor manager for data collection,
|
||||
* the begin function should be used instead for this purpose.
|
||||
*/
|
||||
demo_ret_code initialize_all_sensors();
|
||||
|
||||
/*!
|
||||
* @brief : This function configures the sensor manager using the provided config file.
|
||||
*
|
||||
* @param[in] config : sensor configuration file
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
demo_ret_code begin(const String& config);
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the selected sensor data.
|
||||
*
|
||||
* @param[in] num : Sensor number
|
||||
* @param[in] data : Pointer to sensor data if it is available, else nullptr
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
demo_ret_code collect_data(uint8_t num, bme68x_data* data[3]);
|
||||
};
|
||||
|
||||
#endif
|
||||
332
libraries/bsec2/examples/bme68x_demo_sample/utils.cpp
Normal file
332
libraries/bsec2/examples/bme68x_demo_sample/utils.cpp
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file utils.cpp
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief utils
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* own header include */
|
||||
#include "utils.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <math.h>
|
||||
|
||||
uint64_t utils::_tick_ms;
|
||||
uint64_t utils::_tick_over_flow_cnt;
|
||||
SdFat utils::_sd;
|
||||
RTC_PCF8523 utils::_rtc;
|
||||
char utils::_file_seed[DATA_LOG_FILE_SEED_SIZE];
|
||||
uint32_t utils::_file_data_pos = 0;
|
||||
bool utils::_is_conf_available;
|
||||
|
||||
/*!
|
||||
* @brief This function creates the random alphanumeric file seed for the log file
|
||||
*/
|
||||
void utils::create_file_seed()
|
||||
{
|
||||
/* setup an alphanumeric characters buffer to choose from */
|
||||
const char *letters = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
/* for each character of the file seed, randomly select one from the buffer */
|
||||
for (uint32_t seed_char = 0; seed_char < 16; seed_char++)
|
||||
{
|
||||
uint32_t rand_c = random(0, 36);
|
||||
_file_seed[seed_char] = letters[rand_c];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function is a callback function to set the correct date for modified SD-card files
|
||||
*/
|
||||
void utils::date_time(uint16_t* date, uint16_t* time)
|
||||
{
|
||||
DateTime now = _rtc.now();
|
||||
/* return date using FAT_DATE macro to format fields */
|
||||
*date = FAT_DATE(now.year(), now.month(), now.day());
|
||||
/* return time using FAT_TIME macro to format fields */
|
||||
*time = FAT_TIME(now.hour(), now.minute(), now.second());
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function initializes the module
|
||||
*/
|
||||
demo_ret_code utils::begin()
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
|
||||
if (!_sd.begin(PIN_SD_CS, SPI_EIGHTH_SPEED))
|
||||
{
|
||||
ret_code = EDK_SD_CARD_INIT_ERROR;
|
||||
}
|
||||
else if (!_rtc.begin())
|
||||
{
|
||||
ret_code = EDK_DATALOGGER_RTC_BEGIN_WARNING;
|
||||
}
|
||||
else if (!_rtc.initialized() || _rtc.lostPower())
|
||||
{
|
||||
_rtc.adjust(DateTime(F(__DATE__), F(__TIME__)) - TimeSpan((int32_t)(TIMEZONE * 3600)));
|
||||
|
||||
ret_code = EDK_DATALOGGER_RTC_ADJUST_WARNING;
|
||||
}
|
||||
|
||||
randomSeed(analogRead(0));
|
||||
|
||||
create_file_seed();
|
||||
|
||||
SdFile::dateTimeCallback(date_time);
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the rtc handle
|
||||
*/
|
||||
RTC_PCF8523& utils::get_rtc()
|
||||
{
|
||||
return _rtc;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the created file seed
|
||||
*/
|
||||
String utils::get_file_seed()
|
||||
{
|
||||
return String(_file_seed);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function creates a mac address string
|
||||
*/
|
||||
String utils::get_mac_address()
|
||||
{
|
||||
uint64_t mac = ESP.getEfuseMac();
|
||||
char *mac_ptr = (char*)&mac;
|
||||
char mac_str[13];
|
||||
|
||||
sprintf(mac_str, "%02X%02X%02X%02X%02X%02X", mac_ptr[0], mac_ptr[1], mac_ptr[2], mac_ptr[3], mac_ptr[4], mac_ptr[5]);
|
||||
|
||||
return String(mac_str);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function creates a date string
|
||||
*/
|
||||
String utils::get_date_time()
|
||||
{
|
||||
char time_buffer[20];
|
||||
DateTime date = _rtc.now();
|
||||
|
||||
sprintf(time_buffer, "%d_%02d_%02d_%02d_%02d", date.year(), date.month(), date.day(), date.hour(), date.minute());
|
||||
|
||||
return String(time_buffer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the first file with provided file extension
|
||||
*/
|
||||
bool utils::get_file_with_extension(String& fName, const String& extension)
|
||||
{
|
||||
File root;
|
||||
File file;
|
||||
char file_name[90];
|
||||
|
||||
if (root.open("/"))
|
||||
{
|
||||
|
||||
while (file.openNext(&root, O_READ))
|
||||
{
|
||||
|
||||
if (file.isFile())
|
||||
{
|
||||
file.getName(file_name, sizeof(file_name));
|
||||
|
||||
if (String(file_name).endsWith(extension))
|
||||
{
|
||||
file.close();
|
||||
fName = String(file_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrieves the latest file with provided file extension
|
||||
*/
|
||||
bool utils::get_latest_file_with_extension(String& fName, const String& extension)
|
||||
{
|
||||
File root;
|
||||
File file;
|
||||
char file_name[90];
|
||||
bool flag = false;
|
||||
|
||||
if (root.open("/"))
|
||||
{
|
||||
|
||||
while (file.openNext(&root, O_READ))
|
||||
{
|
||||
|
||||
if (file.isFile())
|
||||
{
|
||||
file.getName(file_name, sizeof(file_name));
|
||||
|
||||
if (String(file_name).endsWith(extension))
|
||||
{
|
||||
file.close();
|
||||
fName = String(file_name);
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function retrives the bsec configuration string from the provided file
|
||||
*/
|
||||
demo_ret_code utils::get_bsec_config(const String& file_name, uint8_t config_str[BSEC_MAX_PROPERTY_BLOB_SIZE])
|
||||
{
|
||||
demo_ret_code ret_code = EDK_OK;
|
||||
uint32_t config_str_len;
|
||||
|
||||
File configFile;
|
||||
if (!configFile.open(file_name.c_str(), O_RDWR))
|
||||
{
|
||||
ret_code = EDK_BSEC_CONFIG_STR_FILE_ERROR;
|
||||
}
|
||||
else if (configFile.read(&config_str_len, sizeof(uint32_t)) != sizeof(uint32_t))
|
||||
{
|
||||
ret_code = EDK_BSEC_CONFIG_STR_READ_ERROR;
|
||||
}
|
||||
else if (config_str_len != BSEC_MAX_PROPERTY_BLOB_SIZE)
|
||||
{
|
||||
ret_code = EDK_BSEC_CONFIG_STR_SIZE_ERROR;
|
||||
}
|
||||
else if (configFile.read(config_str, config_str_len) != config_str_len)
|
||||
{
|
||||
ret_code = EDK_BSEC_CONFIG_STR_READ_ERROR;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief This function returns the tick value (ms)
|
||||
*/
|
||||
uint64_t utils::get_tick_ms(void)
|
||||
{
|
||||
uint64_t time_ms = millis();
|
||||
|
||||
if (_tick_ms > time_ms) /* An overflow occurred */
|
||||
{
|
||||
_tick_over_flow_cnt++;
|
||||
}
|
||||
_tick_ms = time_ms;
|
||||
return time_ms + (_tick_over_flow_cnt * INT64_C(0xFFFFFFFF));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief : This function reads the size of bytes from the file of given fileExtension
|
||||
*/
|
||||
demo_ret_code utils::read_file(const String& file_extension, size_t size, char *file_data)
|
||||
{
|
||||
File file;
|
||||
demo_ret_code ret_code;
|
||||
static String file_name;
|
||||
static bool first_time = true;
|
||||
memset(file_data, 0, size); /* Clears the previous data if any */
|
||||
ret_code = utils::begin(); /* Initializes the SD card module */
|
||||
|
||||
size = size - 1;
|
||||
|
||||
if (ret_code >= EDK_OK)
|
||||
{
|
||||
|
||||
if (first_time)
|
||||
{
|
||||
|
||||
if (file_extension == BME68X_LABEL_INFO_FILE_EXT)
|
||||
{
|
||||
/* check for a file with given extension */
|
||||
_is_conf_available = utils::get_latest_file_with_extension(file_name, file_extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check for a file with given extension */
|
||||
_is_conf_available = utils::get_file_with_extension(file_name, file_extension);
|
||||
}
|
||||
}
|
||||
|
||||
if (_is_conf_available)
|
||||
{
|
||||
|
||||
if (!file.open(file_name.c_str(), O_READ)) /* open the given file in read mode */
|
||||
{
|
||||
return EDK_FILE_OPEN_ERROR;
|
||||
}
|
||||
first_time = false;
|
||||
file.seek(_file_data_pos); /* sets the position of the file to a particular byte */
|
||||
|
||||
if (file.available())
|
||||
{
|
||||
file.read(file_data, size); /* reads the given number of bytes of data */
|
||||
_file_data_pos = file.position(); /* save the file position indicator for next read */
|
||||
file.close(); /* closes the file */
|
||||
return EDK_OK;
|
||||
}
|
||||
file.close();
|
||||
_file_data_pos = 0; /* resets the file position indicator */
|
||||
first_time = true;
|
||||
return EDK_END_OF_FILE;
|
||||
}
|
||||
return EDK_EXTENSION_NOT_AVAILABLE;
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
168
libraries/bsec2/examples/bme68x_demo_sample/utils.h
Normal file
168
libraries/bsec2/examples/bme68x_demo_sample/utils.h
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*!
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file utils.h
|
||||
* @date 03 Jan 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
* @brief Header file for the datalogger utils
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DATALOGGER_UTILS_H
|
||||
#define DATALOGGER_UTILS_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <SdFat.h>
|
||||
#include <RTClib.h>
|
||||
#include "demo_app.h"
|
||||
|
||||
#define BME68X_RAWDATA_FILE_EXT ".bmerawdata"
|
||||
#define BME68X_LABEL_INFO_FILE_EXT ".bmelabelinfo"
|
||||
#define BME68X_CONFIG_FILE_EXT ".bmeconfig"
|
||||
#define BSEC_CONFIG_FILE_EXT ".config"
|
||||
#define AI_CONFIG_FILE_EXT ".aiconfig"
|
||||
#define AI_DATA_FILE_EXT ".aipredictions"
|
||||
#define FILE_SIZE_LIMIT UINT32_C(311427072)
|
||||
#define TIMEZONE 2.0
|
||||
#define DATA_LOG_FILE_SEED_SIZE UINT8_C(17)
|
||||
#define PIN_SD_CS UINT8_C(33)
|
||||
|
||||
|
||||
class utils
|
||||
{
|
||||
private:
|
||||
static uint64_t _tick_ms;
|
||||
static uint64_t _tick_over_flow_cnt;
|
||||
static SdFat _sd;
|
||||
static RTC_PCF8523 _rtc;
|
||||
static char _file_seed[DATA_LOG_FILE_SEED_SIZE];
|
||||
static uint32_t _file_data_pos;
|
||||
static bool _is_conf_available;
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* @brief : This function creates the random alphanumeric file seed for the log file
|
||||
*/
|
||||
static void create_file_seed();
|
||||
public:
|
||||
/*!
|
||||
* @brief : This function is a callback function to set the correct date for modified SD-card files
|
||||
*/
|
||||
static void date_time(uint16_t* date, uint16_t* time);
|
||||
|
||||
/*!
|
||||
* @brief : This function initializes the module
|
||||
*
|
||||
* @return a bosch return code
|
||||
*/
|
||||
static demo_ret_code begin();
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the rtc handle
|
||||
*
|
||||
* @return a reference to the rtc handle
|
||||
*/
|
||||
static RTC_PCF8523& get_rtc();
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the created file seed
|
||||
*
|
||||
* @return the created file seed (16 random alphanumerical characters)
|
||||
*/
|
||||
static String get_file_seed();
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a mac address string
|
||||
*
|
||||
* @return the mac address string
|
||||
*/
|
||||
static String get_mac_address();
|
||||
|
||||
/*!
|
||||
* @brief : This function creates a date string
|
||||
*
|
||||
* @return the date string
|
||||
*/
|
||||
static String get_date_time();
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the first file with provided file extension
|
||||
*
|
||||
* @param[out] fName : the filename found
|
||||
* @param[in] extension : the file extension
|
||||
*
|
||||
* @return the date string
|
||||
*/
|
||||
static bool get_file_with_extension(String& fName, const String& extension);
|
||||
|
||||
/*!
|
||||
* @brief : This function retrieves the latest file with provided file extension
|
||||
*
|
||||
* @param[out] fName : the filename found
|
||||
* @param[in] extension : the file extension
|
||||
*
|
||||
* @return the date string
|
||||
*/
|
||||
static bool get_latest_file_with_extension(String& fName, const String& extension);
|
||||
|
||||
/*!
|
||||
* @brief : This function retrives the bsec configuration string from the provided file
|
||||
*
|
||||
* @param[in] fileName : the bsec configuration filename
|
||||
* @param[out] configStr: the configuration string
|
||||
*
|
||||
* @return a bosch return code
|
||||
*/
|
||||
static demo_ret_code get_bsec_config(const String& file_name, uint8_t config_str[BSEC_MAX_PROPERTY_BLOB_SIZE]);
|
||||
|
||||
/*!
|
||||
* @brief : This function returns the tick value (ms)
|
||||
*
|
||||
* @return tick value in milliseconds
|
||||
*/
|
||||
static uint64_t get_tick_ms(void);
|
||||
|
||||
/*!
|
||||
* @brief : This function reads size of bytes from the file of given fileExtension
|
||||
*
|
||||
* @param[in] fileExtension : file extension to search for a file in SD card
|
||||
* @param[in] size : number of bytes to read
|
||||
* @param[in] fileData : pointer to store the read data
|
||||
*
|
||||
* @return a bosch return code
|
||||
*/
|
||||
static demo_ret_code read_file(const String& file_extension, size_t size, char *file_data);
|
||||
};
|
||||
#endif
|
||||
12
libraries/bsec2/examples/generic_examples/Readme.md
Normal file
12
libraries/bsec2/examples/generic_examples/Readme.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
The generic_examples are provided only for a single sensor implementation.
|
||||
If multiple sensors are used kindly refer to x8_board_examples where support for 8 sensors are demonstrated.
|
||||
|
||||
|
||||
basic_config_state.ino example supports regression as well as classification outputs.
|
||||
However BSEC supports only one mode at any given point of time.
|
||||
Ensure to define the output mode required in the example code before compilation.
|
||||
|
||||
Set the OUTPUT_MODE macro to CLASSIFICATION for the classification output of the BSEC algorithm (default).
|
||||
#define OUTPUT_MODE CLASSIFICATION
|
||||
Set the OUTPUT_MODE macro to REGRESSION for the regression output of the BSEC algorithm.
|
||||
#define OUTPUT_MODE REGRESSION
|
||||
223
libraries/bsec2/examples/generic_examples/basic/basic.ino
Normal file
223
libraries/bsec2/examples/generic_examples/basic/basic.ino
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/**
|
||||
* Copyright (C) 2021 Bosch Sensortec GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/* If compiling this examples leads to an 'undefined reference error', refer to the README
|
||||
* at https://github.com/BoschSensortec/Bosch-BSEC2-Library
|
||||
*/
|
||||
/* The new sensor needs to be conditioned before the example can work reliably. You may run this
|
||||
* example for 24hrs to let the sensor stabilize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* basic.ino sketch :
|
||||
* This is an example for illustrating the BSEC virtual outputs and
|
||||
* which has been designed to work with Adafruit ESP8266 Board
|
||||
*/
|
||||
|
||||
#include <bsec2.h>
|
||||
|
||||
/* Macros used */
|
||||
#define PANIC_LED LED_BUILTIN
|
||||
#define ERROR_DUR 1000
|
||||
|
||||
#define SAMPLE_RATE BSEC_SAMPLE_RATE_ULP
|
||||
|
||||
/* Helper functions declarations */
|
||||
/**
|
||||
* @brief : This function toggles the led when a fault was detected
|
||||
*/
|
||||
void errLeds(void);
|
||||
|
||||
/**
|
||||
* @brief : This function checks the BSEC status, prints the respective error code. Halts in case of error
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void checkBsecStatus(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function is called by the BSEC library when a new output is available
|
||||
* @param[in] input : BME68X sensor data before processing
|
||||
* @param[in] outputs : Processed BSEC BSEC output data
|
||||
* @param[in] bsec : Instance of BSEC2 calling the callback
|
||||
*/
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec);
|
||||
|
||||
/* Create an object of the class Bsec2 */
|
||||
Bsec2 envSensor;
|
||||
|
||||
/* Entry point for the example */
|
||||
void setup(void)
|
||||
{
|
||||
/* Desired subscription list of BSEC2 outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_IAQ,
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_STABILIZATION_STATUS,
|
||||
BSEC_OUTPUT_RUN_IN_STATUS,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
|
||||
BSEC_OUTPUT_STATIC_IAQ,
|
||||
BSEC_OUTPUT_CO2_EQUIVALENT,
|
||||
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
|
||||
BSEC_OUTPUT_GAS_PERCENTAGE,
|
||||
BSEC_OUTPUT_COMPENSATED_GAS
|
||||
};
|
||||
|
||||
/* Initialize the communication interfaces */
|
||||
Serial.begin(115200);
|
||||
Wire.begin();
|
||||
pinMode(PANIC_LED, OUTPUT);
|
||||
|
||||
/* Valid for boards with USB-COM. Wait until the port is open */
|
||||
while(!Serial) delay(10);
|
||||
|
||||
/* Initialize the library and interfaces */
|
||||
if (!envSensor.begin(BME68X_I2C_ADDR_LOW, Wire))
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
|
||||
/*
|
||||
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
|
||||
* Please update the offset value after testing this on your product
|
||||
*/
|
||||
if (SAMPLE_RATE == BSEC_SAMPLE_RATE_ULP)
|
||||
{
|
||||
envSensor.setTemperatureOffset(TEMP_OFFSET_ULP);
|
||||
}
|
||||
else if (SAMPLE_RATE == BSEC_SAMPLE_RATE_LP)
|
||||
{
|
||||
envSensor.setTemperatureOffset(TEMP_OFFSET_LP);
|
||||
}
|
||||
|
||||
/* Subsribe to the desired BSEC2 outputs */
|
||||
if (!envSensor.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLE_RATE))
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
|
||||
/* Whenever new data is available call the newDataCallback function */
|
||||
envSensor.attachCallback(newDataCallback);
|
||||
|
||||
Serial.println("BSEC library version " + \
|
||||
String(envSensor.version.major) + "." \
|
||||
+ String(envSensor.version.minor) + "." \
|
||||
+ String(envSensor.version.major_bugfix) + "." \
|
||||
+ String(envSensor.version.minor_bugfix));
|
||||
}
|
||||
|
||||
/* Function that is looped forever */
|
||||
void loop(void)
|
||||
{
|
||||
/* Call the run function often so that the library can
|
||||
* check if it is time to read new data from the sensor
|
||||
* and process it.
|
||||
*/
|
||||
if (!envSensor.run())
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
}
|
||||
|
||||
void errLeds(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
digitalWrite(PANIC_LED, HIGH);
|
||||
delay(ERROR_DUR);
|
||||
digitalWrite(PANIC_LED, LOW);
|
||||
delay(ERROR_DUR);
|
||||
}
|
||||
}
|
||||
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
|
||||
{
|
||||
if (!outputs.nOutputs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("BSEC outputs:\n\tTime stamp = " + String((int) (outputs.output[0].time_stamp / INT64_C(1000000))));
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
{
|
||||
const bsecData output = outputs.output[i];
|
||||
switch (output.sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_IAQ:
|
||||
Serial.println("\tIAQ = " + String(output.signal));
|
||||
Serial.println("\tIAQ accuracy = " + String((int) output.accuracy));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
Serial.println("\tTemperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
Serial.println("\tPressure = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
Serial.println("\tHumidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
Serial.println("\tGas resistance = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_STABILIZATION_STATUS:
|
||||
Serial.println("\tStabilization status = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RUN_IN_STATUS:
|
||||
Serial.println("\tRun in status = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
Serial.println("\tCompensated temperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
Serial.println("\tCompensated humidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_STATIC_IAQ:
|
||||
Serial.println("\tStatic IAQ = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
||||
Serial.println("\tCO2 Equivalent = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
||||
Serial.println("\tbVOC equivalent = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
||||
Serial.println("\tGas percentage = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_COMPENSATED_GAS:
|
||||
Serial.println("\tCompensated gas = " + String(output.signal));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkBsecStatus(Bsec2 bsec)
|
||||
{
|
||||
if (bsec.status < BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC error code : " + String(bsec.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.status > BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC warning code : " + String(bsec.status));
|
||||
}
|
||||
|
||||
if (bsec.sensor.status < BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X error code : " + String(bsec.sensor.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.sensor.status > BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X warning code : " + String(bsec.sensor.status));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
/**
|
||||
* Copyright (C) 2021 Bosch Sensortec GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/* If compiling this examples leads to an 'undefined reference error', refer to the README
|
||||
* at https://github.com/BoschSensortec/Bosch-BSEC2-Library
|
||||
*/
|
||||
/* The new sensor needs to be conditioned before the example can work reliably. You may run this
|
||||
* example for 24hrs to let the sensor stabilize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* basic_config_state.ino sketch :
|
||||
* This is an example for integration of BSEC2x library using configuration setting and has been
|
||||
* tested with Adafruit ESP8266 Board
|
||||
*
|
||||
* For quick integration test, example code can be used with configuration file under folder
|
||||
* Bosch_BSEC2_Library/src/config/FieldAir_HandSanitizer (Configuration file added as simple
|
||||
* code example for integration but not optimized on classification performance)
|
||||
* Config string for H2S and NonH2S target classes is also kept for reference (Suitable for
|
||||
* lab-based characterization of the sensor)
|
||||
*/
|
||||
|
||||
/* Use the Espressif EEPROM library. Skip otherwise */
|
||||
#if defined(ARDUINO_ARCH_ESP32) || (ARDUINO_ARCH_ESP8266)
|
||||
#include <EEPROM.h>
|
||||
#define USE_EEPROM
|
||||
#endif
|
||||
|
||||
#include <bsec2.h>
|
||||
|
||||
#define CLASSIFICATION 1
|
||||
#define REGRESSION 2
|
||||
|
||||
/* Configuration for two class classification used here
|
||||
* For four class classification please use configuration under config/FieldAir_HandSanitizer_Onion_Cinnamon
|
||||
*/
|
||||
/* Note :
|
||||
For the classification output from BSEC algorithm set OUTPUT_MODE macro to CLASSIFICATION.
|
||||
For the regression output from BSEC algorithm set OUTPUT_MODE macro to REGRESSION.
|
||||
*/
|
||||
#define OUTPUT_MODE CLASSIFICATION
|
||||
|
||||
#if (OUTPUT_MODE == CLASSIFICATION)
|
||||
const uint8_t bsec_config[] = {
|
||||
#include "config/FieldAir_HandSanitizer/bsec_selectivity.txt"
|
||||
};
|
||||
#elif (OUTPUT_MODE == REGRESSION)
|
||||
const uint8_t bsec_config[] = {
|
||||
#include "config/bme688/bme688_reg_18v_300s_4d/bsec_selectivity.txt"
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Macros used */
|
||||
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) /* 360 minutes - 4 times a day */
|
||||
#define PANIC_LED LED_BUILTIN
|
||||
#define ERROR_DUR 1000
|
||||
|
||||
/* Helper functions declarations */
|
||||
/**
|
||||
* @brief : This function toggles the led continuously with one second delay
|
||||
*/
|
||||
void errLeds(void);
|
||||
|
||||
/**
|
||||
* @brief : This function checks the BSEC status, prints the respective error code. Halts in case of error
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void checkBsecStatus(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function updates/saves BSEC state
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void updateBsecState(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function is called by the BSEC library when a new output is available
|
||||
* @param[in] input : BME68X sensor data before processing
|
||||
* @param[in] outputs : Processed BSEC BSEC output data
|
||||
* @param[in] bsec : Instance of BSEC2 calling the callback
|
||||
*/
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function retrieves the existing state
|
||||
* @param : Bsec2 class object
|
||||
*/
|
||||
bool loadState(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function writes the state into EEPROM
|
||||
* @param : Bsec2 class object
|
||||
*/
|
||||
bool saveState(Bsec2 bsec);
|
||||
|
||||
/* Create an object of the class Bsec2 */
|
||||
Bsec2 envSensor;
|
||||
#ifdef USE_EEPROM
|
||||
static uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
#endif
|
||||
/* Gas estimate names will be according to the configuration classes used */
|
||||
const String gasName[] = { "Field Air", "Hand sanitizer", "Undefined 3", "Undefined 4"};
|
||||
|
||||
/* Entry point for the example */
|
||||
void setup(void)
|
||||
{
|
||||
#if (OUTPUT_MODE == CLASSIFICATION)
|
||||
/* Desired subscription list of BSEC2 outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_RAW_GAS_INDEX,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_1,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_2,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_3,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_4
|
||||
};
|
||||
#elif (OUTPUT_MODE == REGRESSION)
|
||||
/* Desired subscription list of BSEC2 outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_RAW_GAS_INDEX,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_1,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_2,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_3,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_4
|
||||
};
|
||||
#endif
|
||||
|
||||
Serial.begin(115200);
|
||||
#ifdef USE_EEPROM
|
||||
EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1);
|
||||
#endif
|
||||
Wire.begin();
|
||||
pinMode(PANIC_LED, OUTPUT);
|
||||
|
||||
/* Valid for boards with USB-COM. Wait until the port is open */
|
||||
while (!Serial) delay(10);
|
||||
|
||||
/* Initialize the library and interfaces */
|
||||
if (!envSensor.begin(BME68X_I2C_ADDR_LOW, Wire))
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
|
||||
/* Load the configuration string that stores information on how to classify the detected gas */
|
||||
if (!envSensor.setConfig(bsec_config))
|
||||
{
|
||||
checkBsecStatus (envSensor);
|
||||
}
|
||||
|
||||
/* Copy state from the EEPROM to the algorithm */
|
||||
if (!loadState(envSensor))
|
||||
{
|
||||
checkBsecStatus (envSensor);
|
||||
}
|
||||
|
||||
/* Subscribe for the desired BSEC2 outputs */
|
||||
if (!envSensor.updateSubscription(sensorList, ARRAY_LEN(sensorList), BSEC_SAMPLE_RATE_SCAN))
|
||||
{
|
||||
checkBsecStatus (envSensor);
|
||||
}
|
||||
|
||||
/* Whenever new data is available call the newDataCallback function */
|
||||
envSensor.attachCallback(newDataCallback);
|
||||
|
||||
Serial.println("\nBSEC library version " + \
|
||||
String(envSensor.version.major) + "." \
|
||||
+ String(envSensor.version.minor) + "." \
|
||||
+ String(envSensor.version.major_bugfix) + "." \
|
||||
+ String(envSensor.version.minor_bugfix));
|
||||
}
|
||||
|
||||
/* Function that is looped forever */
|
||||
void loop(void)
|
||||
{
|
||||
/* Call the run function often so that the library can
|
||||
* check if it is time to read new data from the sensor
|
||||
* and process it.
|
||||
*/
|
||||
if (!envSensor.run()) {
|
||||
checkBsecStatus (envSensor);
|
||||
}
|
||||
}
|
||||
|
||||
void errLeds(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
digitalWrite(PANIC_LED, HIGH);
|
||||
delay(ERROR_DUR);
|
||||
digitalWrite(PANIC_LED, LOW);
|
||||
delay(ERROR_DUR);
|
||||
}
|
||||
}
|
||||
|
||||
void updateBsecState(Bsec2 bsec)
|
||||
{
|
||||
static uint16_t stateUpdateCounter = 0;
|
||||
bool update = false;
|
||||
|
||||
if (!stateUpdateCounter || (stateUpdateCounter * STATE_SAVE_PERIOD) < millis())
|
||||
{
|
||||
/* Update every STATE_SAVE_PERIOD minutes */
|
||||
update = true;
|
||||
stateUpdateCounter++;
|
||||
}
|
||||
|
||||
if (update && !saveState(bsec))
|
||||
checkBsecStatus(bsec);
|
||||
}
|
||||
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
|
||||
{
|
||||
if (!outputs.nOutputs)
|
||||
return;
|
||||
|
||||
Serial.println("BSEC outputs:\n\tTime stamp = " + String((int) (outputs.output[0].time_stamp / INT64_C(1000000))));
|
||||
uint8_t index = 0;
|
||||
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
{
|
||||
const bsecData output = outputs.output[i];
|
||||
switch (output.sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
Serial.println("\tTemperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
Serial.println("\tPressure = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
Serial.println("\tHumidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
Serial.println("\tGas resistance = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS_INDEX:
|
||||
Serial.println("\tGas index = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
Serial.println("\tCompensated temperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
Serial.println("\tCompensated humidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_1:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_2:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_3:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_4:
|
||||
index = (output.sensor_id - BSEC_OUTPUT_GAS_ESTIMATE_1);
|
||||
if (index == 0) // The four classes are updated from BSEC with same accuracy, thus printing is done just once.
|
||||
{
|
||||
Serial.println("\tAccuracy = " + String(output.accuracy));
|
||||
}
|
||||
Serial.println("\tClass " + String(index + 1) + " probability = " + String(output.signal * 100) + "%");
|
||||
break;
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_1:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_2:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_3:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_4:
|
||||
index = (output.sensor_id - BSEC_OUTPUT_REGRESSION_ESTIMATE_1);
|
||||
if (index == 0) // The four targets are updated from BSEC with same accuracy, thus printing is done just once.
|
||||
{
|
||||
Serial.println("\tAccuracy = " + String(output.accuracy));
|
||||
}
|
||||
Serial.println("\tTarget " + String(index + 1) + " = " + String(output.signal * 100));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateBsecState(envSensor);
|
||||
}
|
||||
|
||||
void checkBsecStatus(Bsec2 bsec)
|
||||
{
|
||||
if (bsec.status < BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC error code : " + String(bsec.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
} else if (bsec.status > BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC warning code : " + String(bsec.status));
|
||||
}
|
||||
|
||||
if (bsec.sensor.status < BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X error code : " + String(bsec.sensor.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
} else if (bsec.sensor.status > BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X warning code : " + String(bsec.sensor.status));
|
||||
}
|
||||
}
|
||||
|
||||
bool loadState(Bsec2 bsec)
|
||||
{
|
||||
#ifdef USE_EEPROM
|
||||
|
||||
|
||||
if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE)
|
||||
{
|
||||
/* Existing state in EEPROM */
|
||||
Serial.println("Reading state from EEPROM");
|
||||
Serial.print("State file: ");
|
||||
for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
{
|
||||
bsecState[i] = EEPROM.read(i + 1);
|
||||
Serial.print(String(bsecState[i], HEX) + ", ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
if (!bsec.setState(bsecState))
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
/* Erase the EEPROM with zeroes */
|
||||
Serial.println("Erasing EEPROM");
|
||||
|
||||
for (uint8_t i = 0; i <= BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
EEPROM.write(i, 0);
|
||||
|
||||
EEPROM.commit();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool saveState(Bsec2 bsec)
|
||||
{
|
||||
#ifdef USE_EEPROM
|
||||
if (!bsec.getState(bsecState))
|
||||
return false;
|
||||
|
||||
Serial.println("Writing state to EEPROM");
|
||||
Serial.print("State file: ");
|
||||
|
||||
for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
{
|
||||
EEPROM.write(i + 1, bsecState[i]);
|
||||
Serial.print(String(bsecState[i], HEX) + ", ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE);
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32dev]
|
||||
platform = espressif32@6.6.0
|
||||
board = esp32dev
|
||||
framework = espidf
|
||||
platform_packages =
|
||||
platformio/framework-espidf@~3.50201.0
|
||||
lib_deps =
|
||||
../../../
|
||||
BME68x Sensor library=https://github.com/luar123/Bosch-BME68x-Library.git
|
||||
https://github.com/natanaeljr/esp32-I2Cbus
|
||||
monitor_speed = 115200
|
||||
274
libraries/bsec2/examples/generic_examples/basic_idf/src/main.cpp
Normal file
274
libraries/bsec2/examples/generic_examples/basic_idf/src/main.cpp
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/**
|
||||
* Copyright (C) 2021 Bosch Sensortec GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/* If compiling this examples leads to an 'undefined reference error', refer to the README
|
||||
* at https://github.com/BoschSensortec/Bosch-BSEC2-Library
|
||||
*/
|
||||
/* The new sensor needs to be conditioned before the example can work reliably. You may run this
|
||||
* example for 24hrs to let the sensor stabilize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* basic.ino sketch :
|
||||
* This is an example for illustrating the BSEC virtual outputs and
|
||||
* which has been designed to work with Adafruit ESP8266 Board
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "I2Cbus.hpp"
|
||||
|
||||
#define BME688_ADD 0x77
|
||||
|
||||
static const char* TAG = "main";
|
||||
|
||||
#include <bsec2.h>
|
||||
|
||||
/* Macros used */
|
||||
#define PANIC_LED GPIO_NUM_5
|
||||
#define ERROR_DUR 1000
|
||||
|
||||
#define SAMPLE_RATE BSEC_SAMPLE_RATE_LP
|
||||
|
||||
/* Helper functions declarations */
|
||||
/**
|
||||
* @brief : This function toggles the led when a fault was detected
|
||||
*/
|
||||
void errLeds(void);
|
||||
|
||||
/**
|
||||
* @brief : This function checks the BSEC status, prints the respective error code. Halts in case of error
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void checkBsecStatus(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function is called by the BSEC library when a new output is available
|
||||
* @param[in] input : BME68X sensor data before processing
|
||||
* @param[in] outputs : Processed BSEC BSEC output data
|
||||
* @param[in] bsec : Instance of BSEC2 calling the callback
|
||||
*/
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec);
|
||||
|
||||
/* Create an object of the class Bsec2 */
|
||||
Bsec2 envSensor;
|
||||
|
||||
/* Function wrappers */
|
||||
int8_t read_bytes_wrapper(uint8_t a_register, uint8_t *data, uint32_t len, void *intfPtr) {
|
||||
return static_cast<I2C_t *>(intfPtr)->readBytes(BME688_ADD, a_register, len, data)==ESP_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
int8_t write_bytes_wrapper(uint8_t a_register, const uint8_t *data, uint32_t len,
|
||||
void *intfPtr) {
|
||||
return static_cast<I2C_t *>(intfPtr)->writeBytes(BME688_ADD, a_register, len, data)==ESP_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); }
|
||||
void IRAM_ATTR delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
|
||||
uint32_t IRAM_ATTR micros() { return (uint32_t) esp_timer_get_time(); }
|
||||
|
||||
void delay_microseconds_safe(uint32_t us) { // avoids CPU locks that could trigger WDT or affect WiFi/BT stability
|
||||
uint32_t start = micros();
|
||||
|
||||
const uint32_t lag = 5000; // microseconds, specifies the maximum time for a CPU busy-loop.
|
||||
// it must be larger than the worst-case duration of a delay(1) call (hardware tasks)
|
||||
// 5ms is conservative, it could be reduced when exact BT/WiFi stack delays are known
|
||||
if (us > lag) {
|
||||
delay((us - lag) / 1000UL); // note: in disabled-interrupt contexts delay() won't actually sleep
|
||||
while (micros() - start < us - lag)
|
||||
delay(1); // in those cases, this loop allows to yield for BT/WiFi stack tasks
|
||||
}
|
||||
while (micros() - start < us) // fine delay the remaining usecs
|
||||
;
|
||||
}
|
||||
|
||||
void delay_us(uint32_t period, void *intfPtr) {
|
||||
delay_microseconds_safe(period);
|
||||
}
|
||||
|
||||
/* Entry point for the example */
|
||||
void setup(void)
|
||||
{
|
||||
/* Desired subscription list of BSEC2 outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_IAQ,
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_STABILIZATION_STATUS,
|
||||
BSEC_OUTPUT_RUN_IN_STATUS,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
|
||||
BSEC_OUTPUT_STATIC_IAQ,
|
||||
BSEC_OUTPUT_CO2_EQUIVALENT,
|
||||
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
|
||||
BSEC_OUTPUT_GAS_PERCENTAGE,
|
||||
BSEC_OUTPUT_COMPENSATED_GAS
|
||||
};
|
||||
|
||||
/* Initialize the communication interfaces */
|
||||
i2c0.begin(GPIO_NUM_3,GPIO_NUM_0);
|
||||
gpio_set_direction(PANIC_LED, GPIO_MODE_OUTPUT);
|
||||
|
||||
|
||||
/* Initialize the library and interfaces */
|
||||
if (!envSensor.begin(BME68X_I2C_INTF, read_bytes_wrapper, write_bytes_wrapper, delay_us, (void *) &i2c0, millis))
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
|
||||
/*
|
||||
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
|
||||
* Please update the offset value after testing this on your product
|
||||
*/
|
||||
if (SAMPLE_RATE == BSEC_SAMPLE_RATE_ULP)
|
||||
{
|
||||
envSensor.setTemperatureOffset(TEMP_OFFSET_ULP);
|
||||
}
|
||||
else if (SAMPLE_RATE == BSEC_SAMPLE_RATE_LP)
|
||||
{
|
||||
envSensor.setTemperatureOffset(TEMP_OFFSET_LP);
|
||||
}
|
||||
|
||||
/* Subsribe to the desired BSEC2 outputs */
|
||||
if (!envSensor.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLE_RATE))
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
|
||||
/* Whenever new data is available call the newDataCallback function */
|
||||
envSensor.attachCallback(newDataCallback);
|
||||
|
||||
ESP_LOGI(TAG, "BSEC library version %u.%u.%u.%u", envSensor.version.major, envSensor.version.minor, envSensor.version.major_bugfix, envSensor.version.minor_bugfix);
|
||||
}
|
||||
|
||||
/* Function that is looped forever */
|
||||
void loop(void)
|
||||
{
|
||||
/* Call the run function often so that the library can
|
||||
* check if it is time to read new data from the sensor
|
||||
* and process it.
|
||||
*/
|
||||
if (!envSensor.run())
|
||||
{
|
||||
checkBsecStatus(envSensor);
|
||||
}
|
||||
}
|
||||
|
||||
void errLeds(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
gpio_set_level(PANIC_LED, 1);
|
||||
vTaskDelay(ERROR_DUR / portTICK_PERIOD_MS);
|
||||
gpio_set_level(PANIC_LED, 0);
|
||||
vTaskDelay(ERROR_DUR / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
|
||||
{
|
||||
if (!outputs.nOutputs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "BSEC outputs:\n\tTime stamp = %d", (int) (outputs.output[0].time_stamp / INT64_C(1000000)));
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
{
|
||||
const bsecData output = outputs.output[i];
|
||||
switch (output.sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_IAQ:
|
||||
ESP_LOGI(TAG, "\tIAQ = %f", output.signal);
|
||||
ESP_LOGI(TAG, "\tIAQ accuracy = %d", (int) output.accuracy);
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
ESP_LOGI(TAG, "\tTemperature = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
ESP_LOGI(TAG, "\tPressure = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
ESP_LOGI(TAG, "\tHumidity = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
ESP_LOGI(TAG, "\tGas resistance = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_STABILIZATION_STATUS:
|
||||
ESP_LOGI(TAG, "\tStabilization status = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_RUN_IN_STATUS:
|
||||
ESP_LOGI(TAG, "\tRun in status = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
ESP_LOGI(TAG, "\tCompensated temperature = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
ESP_LOGI(TAG, "\tCompensated humidity = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_STATIC_IAQ:
|
||||
ESP_LOGI(TAG, "\tStatic IAQ = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
||||
ESP_LOGI(TAG, "\tCO2 Equivalent = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
||||
ESP_LOGI(TAG, "\tbVOC equivalent = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
||||
ESP_LOGI(TAG, "\tGas percentage = %f", output.signal);
|
||||
break;
|
||||
case BSEC_OUTPUT_COMPENSATED_GAS:
|
||||
ESP_LOGI(TAG, "\tCompensated gas = %f", output.signal);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkBsecStatus(Bsec2 bsec)
|
||||
{
|
||||
if (bsec.status < BSEC_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "BSEC error code : %d", bsec.status);
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.status > BSEC_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "BSEC warning code : %d", bsec.status);
|
||||
}
|
||||
|
||||
if (bsec.sensor.status < BME68X_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "BME68X error code : %d", bsec.sensor.status);
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.sensor.status > BME68X_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "BME68X warning code : %d", bsec.sensor.status);
|
||||
}
|
||||
}
|
||||
|
||||
void loop_task(void *pv_params) {
|
||||
setup();
|
||||
while (true) {
|
||||
loop();
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
ESP_LOGI(TAG, "starting");
|
||||
xTaskCreate(loop_task, "loopTask", 8192, nullptr, 1, NULL);
|
||||
}
|
||||
8
libraries/bsec2/examples/x8_board_examples/Readme.md
Normal file
8
libraries/bsec2/examples/x8_board_examples/Readme.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
basic_config_state.ino example supports regression as well as classification outputs.
|
||||
However BSEC supports only one mode at any given point of time.
|
||||
Ensure to define the output mode required in the example code before compilation.
|
||||
|
||||
Set the OUTPUT_MODE macro to CLASSIFICATION for the classification output of the BSEC algorithm (default).
|
||||
#define OUTPUT_MODE CLASSIFICATION
|
||||
Set the OUTPUT_MODE macro to REGRESSION for the regression output of the BSEC algorithm.
|
||||
#define OUTPUT_MODE REGRESSION
|
||||
242
libraries/bsec2/examples/x8_board_examples/basic/basic.ino
Normal file
242
libraries/bsec2/examples/x8_board_examples/basic/basic.ino
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/**
|
||||
Copyright (C) 2021 Bosch Sensortec GmbH
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
*/
|
||||
|
||||
/* The new sensor needs to be conditioned before the example can work reliably. You may run this
|
||||
example for 24hrs to let the sensor stabilize.
|
||||
*/
|
||||
|
||||
/**
|
||||
basic.ino sketch :
|
||||
This is an example for illustrating the BSEC virtual outputs using BME688 Development Kit,
|
||||
which has been designed to work with Adafruit ESP32 Feather Board
|
||||
For more information visit :
|
||||
https://www.bosch-sensortec.com/software-tools/software/bme688-software/
|
||||
*/
|
||||
|
||||
#include <bsec2.h>
|
||||
#include <commMux\commMux.h>
|
||||
|
||||
/* Macros used */
|
||||
/* Number of sensors to operate*/
|
||||
#define NUM_OF_SENS 8
|
||||
#define PANIC_LED LED_BUILTIN
|
||||
#define ERROR_DUR 1000
|
||||
|
||||
#define SAMPLE_RATE BSEC_SAMPLE_RATE_ULP
|
||||
|
||||
/* Helper functions declarations */
|
||||
/**
|
||||
@brief : This function toggles the led when a fault was detected
|
||||
*/
|
||||
void errLeds(void);
|
||||
|
||||
/**
|
||||
@brief : This function checks the BSEC status, prints the respective error code. Halts in case of error
|
||||
@param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void checkBsecStatus(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
@brief : This function is called by the BSEC library when a new output is available
|
||||
@param[in] input : BME68X sensor data before processing
|
||||
@param[in] outputs : Processed BSEC BSEC output data
|
||||
@param[in] bsec : Instance of BSEC2 calling the callback
|
||||
*/
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec);
|
||||
|
||||
/* Create an array of objects of the class Bsec2 */
|
||||
Bsec2 envSensor[NUM_OF_SENS];
|
||||
comm_mux communicationSetup[NUM_OF_SENS];
|
||||
uint8_t bsecMemBlock[NUM_OF_SENS][BSEC_INSTANCE_SIZE];
|
||||
uint8_t sensor = 0;
|
||||
|
||||
/* Entry point for the example */
|
||||
void setup(void)
|
||||
{
|
||||
/* Desired subscription list of BSEC2 outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_IAQ,
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_STABILIZATION_STATUS,
|
||||
BSEC_OUTPUT_RUN_IN_STATUS,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
|
||||
BSEC_OUTPUT_STATIC_IAQ,
|
||||
BSEC_OUTPUT_CO2_EQUIVALENT,
|
||||
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
|
||||
BSEC_OUTPUT_GAS_PERCENTAGE,
|
||||
BSEC_OUTPUT_COMPENSATED_GAS
|
||||
};
|
||||
|
||||
/* Initialize the communication interfaces */
|
||||
Serial.begin(115200);
|
||||
comm_mux_begin(Wire, SPI);
|
||||
pinMode(PANIC_LED, OUTPUT);
|
||||
delay(100);
|
||||
/* Valid for boards with USB-COM. Wait until the port is open */
|
||||
while (!Serial) delay(10);
|
||||
|
||||
for (uint8_t i = 0; i < NUM_OF_SENS; i++)
|
||||
{
|
||||
/* Sets the Communication interface for the sensors */
|
||||
communicationSetup[i] = comm_mux_set_config(Wire, SPI, i, communicationSetup[i]);
|
||||
|
||||
/* Assigning a chunk of memory block to the bsecInstance */
|
||||
envSensor[i].allocateMemory(bsecMemBlock[i]);
|
||||
|
||||
/* Initialize the library and interfaces */
|
||||
if (!envSensor[i].begin(BME68X_SPI_INTF, comm_mux_read, comm_mux_write, comm_mux_delay, &communicationSetup[i]))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
|
||||
* Please update the offset value after testing this on your product
|
||||
*/
|
||||
if (SAMPLE_RATE == BSEC_SAMPLE_RATE_ULP)
|
||||
{
|
||||
envSensor[i].setTemperatureOffset(TEMP_OFFSET_ULP);
|
||||
}
|
||||
else if (SAMPLE_RATE == BSEC_SAMPLE_RATE_LP)
|
||||
{
|
||||
envSensor[i].setTemperatureOffset(TEMP_OFFSET_LP);
|
||||
}
|
||||
|
||||
/* Subscribe to the desired BSEC2 outputs */
|
||||
if (!envSensor[i].updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLE_RATE))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
|
||||
/* Whenever new data is available call the newDataCallback function */
|
||||
envSensor[i].attachCallback(newDataCallback);
|
||||
}
|
||||
|
||||
Serial.println("BSEC library version " + \
|
||||
String(envSensor[0].version.major) + "." \
|
||||
+ String(envSensor[0].version.minor) + "." \
|
||||
+ String(envSensor[0].version.major_bugfix) + "." \
|
||||
+ String(envSensor[0].version.minor_bugfix));
|
||||
}
|
||||
|
||||
/* Function that is looped forever */
|
||||
void loop(void)
|
||||
{
|
||||
/* Call the run function often so that the library can
|
||||
check if it is time to read new data from the sensor
|
||||
and process it.
|
||||
*/
|
||||
for (sensor = 0; sensor < NUM_OF_SENS; sensor++)
|
||||
{
|
||||
if (!envSensor[sensor].run())
|
||||
{
|
||||
checkBsecStatus(envSensor[sensor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void errLeds(void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
digitalWrite(PANIC_LED, HIGH);
|
||||
delay(ERROR_DUR);
|
||||
digitalWrite(PANIC_LED, LOW);
|
||||
delay(ERROR_DUR);
|
||||
}
|
||||
}
|
||||
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
|
||||
{
|
||||
if (!outputs.nOutputs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("BSEC outputs:\n\tSensor num = " + String(sensor));
|
||||
Serial.println("\tTime stamp = " + String((int) (outputs.output[0].time_stamp / INT64_C(1000000))));
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
{
|
||||
const bsecData output = outputs.output[i];
|
||||
switch (output.sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_IAQ:
|
||||
Serial.println("\tIAQ = " + String(output.signal));
|
||||
Serial.println("\tIAQ accuracy = " + String((int) output.accuracy));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
Serial.println("\tTemperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
Serial.println("\tPressure = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
Serial.println("\tHumidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
Serial.println("\tGas resistance = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_STABILIZATION_STATUS:
|
||||
Serial.println("\tStabilization status = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RUN_IN_STATUS:
|
||||
Serial.println("\tRun in status = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
Serial.println("\tCompensated temperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
Serial.println("\tCompensated humidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_STATIC_IAQ:
|
||||
Serial.println("\tStatic IAQ = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
||||
Serial.println("\tCO2 Equivalent = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
||||
Serial.println("\tbVOC equivalent = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
||||
Serial.println("\tGas percentage = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_COMPENSATED_GAS:
|
||||
Serial.println("\tCompensated gas = " + String(output.signal));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkBsecStatus(Bsec2 bsec)
|
||||
{
|
||||
if (bsec.status < BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC error code : " + String(bsec.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.status > BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC warning code : " + String(bsec.status));
|
||||
}
|
||||
|
||||
if (bsec.sensor.status < BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X error code : " + String(bsec.sensor.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
}
|
||||
else if (bsec.sensor.status > BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X warning code : " + String(bsec.sensor.status));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
/**
|
||||
* Copyright (C) 2021 Bosch Sensortec GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/* The new sensor needs to be conditioned before the example can work reliably. You may run this
|
||||
* example for 24hrs to let the sensor stabilize.
|
||||
*/
|
||||
|
||||
/**
|
||||
* basic_config_state.ino sketch :
|
||||
* This is an example for integration of BSEC2x library in BME688 development kit,
|
||||
* which has been designed to work with Adafruit ESP32 Feather Board
|
||||
* For more information visit :
|
||||
* https://www.bosch-sensortec.com/software-tools/software/bme688-software/
|
||||
*
|
||||
* For quick integration test, example code can be used with configuration file under folder
|
||||
* Bosch_BSEC2_Library/src/config/FieldAir_HandSanitizer (Configuration file added as simple
|
||||
* code example for integration but not optimized on classification performance)
|
||||
* Config string for H2S and NonH2S target classes is also kept for reference (Suitable for
|
||||
* lab-based characterization of the sensor)
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
#include <bsec2.h>
|
||||
#include <commMux\commMux.h>
|
||||
/* For two class classification use configuration under config/FieldAir_HandSanitizer */
|
||||
#define CLASSIFICATION 1
|
||||
#define REGRESSION 2
|
||||
|
||||
#define COMPLETED 1
|
||||
|
||||
/* Note :
|
||||
For the classification output from BSEC algorithm set OUTPUT_MODE macro to CLASSIFICATION.
|
||||
For the regression output from BSEC algorithm set OUTPUT_MODE macro to REGRESSION.
|
||||
*/
|
||||
#define OUTPUT_MODE CLASSIFICATION
|
||||
|
||||
#if (OUTPUT_MODE == CLASSIFICATION)
|
||||
const uint8_t bsec_config[] = {
|
||||
#include "config/FieldAir_HandSanitizer/bsec_selectivity.txt"
|
||||
};
|
||||
#elif (OUTPUT_MODE == REGRESSION)
|
||||
const uint8_t bsec_config[] = {
|
||||
#include "config/bme688/bme688_reg_18v_300s_4d/bsec_selectivity.txt"
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Macros used */
|
||||
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) /* 360 minutes - 4 times a day */
|
||||
/* Number of sensors to operate*/
|
||||
#define NUM_OF_SENS 8
|
||||
#define PANIC_LED LED_BUILTIN
|
||||
#define ERROR_DUR 1000
|
||||
|
||||
/* Helper functions declarations */
|
||||
/**
|
||||
* @brief : This function toggles the led continuously with one second delay
|
||||
*/
|
||||
void errLeds(void);
|
||||
|
||||
/**
|
||||
* @brief : This function checks the BSEC status, prints the respective error code. Halts in case of error
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void checkBsecStatus(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function updates/saves BSEC state
|
||||
* @param[in] bsec : Bsec2 class object
|
||||
*/
|
||||
void updateBsecState(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function is called by the BSEC library when a new output is available
|
||||
* @param[in] input : BME68X sensor data before processing
|
||||
* @param[in] outputs : Processed BSEC BSEC output data
|
||||
* @param[in] bsec : Instance of BSEC2 calling the callback
|
||||
*/
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function retrieves the existing state
|
||||
* @param : Bsec2 class object
|
||||
*/
|
||||
bool loadState(Bsec2 bsec);
|
||||
|
||||
/**
|
||||
* @brief : This function writes the state into EEPROM
|
||||
* @param : Bsec2 class object
|
||||
*/
|
||||
bool saveState(Bsec2 bsec);
|
||||
|
||||
/* Create an object of the class Bsec2 */
|
||||
Bsec2 envSensor[NUM_OF_SENS];
|
||||
comm_mux commConfig[NUM_OF_SENS];
|
||||
uint8_t bsecMemBlock[NUM_OF_SENS][BSEC_INSTANCE_SIZE];
|
||||
uint8_t sensor = 0;
|
||||
static uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
/* Gas estimate names will be according to the configuration classes used */
|
||||
const String gasName[] = { "Field Air", "Hand sanitizer", "Undefined 3", "Undefined 4"};
|
||||
|
||||
/* Entry point for the example */
|
||||
void setup(void)
|
||||
{
|
||||
|
||||
#if (OUTPUT_MODE == CLASSIFICATION)
|
||||
/* Desired subscription list of BSEC2 Classification outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_RAW_GAS_INDEX,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_1,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_2,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_3,
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_4
|
||||
};
|
||||
#elif (OUTPUT_MODE == REGRESSION)
|
||||
/* Desired subscription list of BSEC2 Regression outputs */
|
||||
bsecSensor sensorList[] = {
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE,
|
||||
BSEC_OUTPUT_RAW_PRESSURE,
|
||||
BSEC_OUTPUT_RAW_HUMIDITY,
|
||||
BSEC_OUTPUT_RAW_GAS,
|
||||
BSEC_OUTPUT_RAW_GAS_INDEX,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_1,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_2,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_3,
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_4
|
||||
};
|
||||
#endif
|
||||
|
||||
Serial.begin(115200);
|
||||
EEPROM.begin(BSEC_MAX_STATE_BLOB_SIZE + 1);
|
||||
/* Initiate SPI communication */
|
||||
comm_mux_begin(Wire, SPI);
|
||||
pinMode(PANIC_LED, OUTPUT);
|
||||
delay(100);
|
||||
/* Valid for boards with USB-COM. Wait until the port is open */
|
||||
while (!Serial) delay(10);
|
||||
|
||||
uint8_t state_write_otp = 0;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_OF_SENS; i++)
|
||||
{
|
||||
/* Sets the Communication interface for the given sensor */
|
||||
commConfig[i] = comm_mux_set_config(Wire, SPI, i, commConfig[i]);
|
||||
|
||||
/* Assigning a chunk of memory block to the bsecInstance */
|
||||
envSensor[i].allocateMemory(bsecMemBlock[i]);
|
||||
|
||||
/* Initialize the library and interfaces */
|
||||
if (!envSensor[i].begin(BME68X_SPI_INTF, comm_mux_read, comm_mux_write, comm_mux_delay, &commConfig[i]))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
|
||||
/* Load the configuration string that stores information on how to classify the detected gas */
|
||||
if (!envSensor[i].setConfig(bsec_config))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
|
||||
/* Copy state from the EEPROM to the algorithm */
|
||||
if (state_write_otp == 0)
|
||||
{
|
||||
if (!loadState(envSensor[i]))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
state_write_otp = COMPLETED;
|
||||
}
|
||||
|
||||
/* Subscribe for the desired BSEC2 outputs */
|
||||
if (!envSensor[i].updateSubscription(sensorList, ARRAY_LEN(sensorList), BSEC_SAMPLE_RATE_SCAN))
|
||||
{
|
||||
checkBsecStatus (envSensor[i]);
|
||||
}
|
||||
|
||||
/* Whenever new data is available call the newDataCallback function */
|
||||
envSensor[i].attachCallback(newDataCallback);
|
||||
|
||||
updateBsecState(envSensor[i]);
|
||||
}
|
||||
|
||||
Serial.println("\nBSEC library version " + \
|
||||
String(envSensor[0].version.major) + "." \
|
||||
+ String(envSensor[0].version.minor) + "." \
|
||||
+ String(envSensor[0].version.major_bugfix) + "." \
|
||||
+ String(envSensor[0].version.minor_bugfix));
|
||||
}
|
||||
|
||||
/* Function that is looped forever */
|
||||
void loop(void)
|
||||
{
|
||||
/* Call the run function often so that the library can
|
||||
* check if it is time to read new data from the sensor
|
||||
* and process it.
|
||||
*/
|
||||
for (sensor = 0; sensor < NUM_OF_SENS; sensor++)
|
||||
{
|
||||
if (!envSensor[sensor].run())
|
||||
{
|
||||
checkBsecStatus(envSensor[sensor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void errLeds(void)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
digitalWrite(PANIC_LED, HIGH);
|
||||
delay(ERROR_DUR);
|
||||
digitalWrite(PANIC_LED, LOW);
|
||||
delay(ERROR_DUR);
|
||||
}
|
||||
}
|
||||
|
||||
void updateBsecState(Bsec2 bsec)
|
||||
{
|
||||
static uint16_t stateUpdateCounter = 0;
|
||||
bool update = false;
|
||||
|
||||
if (!stateUpdateCounter || (stateUpdateCounter * STATE_SAVE_PERIOD) < millis())
|
||||
{
|
||||
/* Update every STATE_SAVE_PERIOD minutes */
|
||||
update = true;
|
||||
stateUpdateCounter++;
|
||||
}
|
||||
|
||||
if (update && !saveState(bsec))
|
||||
checkBsecStatus(bsec);
|
||||
}
|
||||
|
||||
void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec)
|
||||
{
|
||||
if (!outputs.nOutputs)
|
||||
return;
|
||||
|
||||
Serial.println("BSEC outputs:\n\tSensor num = " + String(sensor));
|
||||
Serial.println("\tTime stamp = " + String((int) (outputs.output[0].time_stamp / INT64_C(1000000))));
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
{
|
||||
const bsecData output = outputs.output[i];
|
||||
switch (output.sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
Serial.println("\tTemperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
Serial.println("\tPressure = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
Serial.println("\tHumidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
Serial.println("\tGas resistance = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS_INDEX:
|
||||
Serial.println("\tGas index = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
Serial.println("\tCompensated temperature = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
Serial.println("\tCompensated humidity = " + String(output.signal));
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_1:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_2:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_3:
|
||||
case BSEC_OUTPUT_GAS_ESTIMATE_4:
|
||||
index = (output.sensor_id - BSEC_OUTPUT_GAS_ESTIMATE_1);
|
||||
if (index == 0) // The four classes are updated from BSEC with same accuracy, thus printing is done just once.
|
||||
{
|
||||
Serial.println("\tAccuracy = " + String((int) output.accuracy));
|
||||
}
|
||||
Serial.println(("\tClass " + String(index + 1) + " probability = ") + String(output.signal * 100) + "%");
|
||||
break;
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_1:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_2:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_3:
|
||||
case BSEC_OUTPUT_REGRESSION_ESTIMATE_4:
|
||||
index = (output.sensor_id - BSEC_OUTPUT_REGRESSION_ESTIMATE_1);
|
||||
if (index == 0) // The four targets are updated from BSEC with same accuracy, thus printing is done just once.
|
||||
{
|
||||
Serial.println("\tAccuracy = " + String(output.accuracy));
|
||||
}
|
||||
Serial.println("\tTarget " + String(index + 1) + " = " + String(output.signal * 100));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void checkBsecStatus(Bsec2 bsec)
|
||||
{
|
||||
if (bsec.status < BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC error code : " + String(bsec.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
} else if (bsec.status > BSEC_OK)
|
||||
{
|
||||
Serial.println("BSEC warning code : " + String(bsec.status));
|
||||
}
|
||||
|
||||
if (bsec.sensor.status < BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X error code : " + String(bsec.sensor.status));
|
||||
errLeds(); /* Halt in case of failure */
|
||||
} else if (bsec.sensor.status > BME68X_OK)
|
||||
{
|
||||
Serial.println("BME68X warning code : " + String(bsec.sensor.status));
|
||||
}
|
||||
}
|
||||
|
||||
bool loadState(Bsec2 bsec)
|
||||
{
|
||||
|
||||
if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE)
|
||||
{
|
||||
/* Existing state in EEPROM */
|
||||
Serial.println("Reading state from EEPROM");
|
||||
Serial.print("State file: ");
|
||||
for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
{
|
||||
bsecState[i] = EEPROM.read(i + 1);
|
||||
Serial.print(String(bsecState[i], HEX) + ", ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
if (!bsec.setState(bsecState))
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
/* Erase the EEPROM with zeroes */
|
||||
Serial.println("Erasing EEPROM");
|
||||
|
||||
for (uint8_t i = 0; i <= BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
EEPROM.write(i, 0);
|
||||
|
||||
EEPROM.commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool saveState(Bsec2 bsec)
|
||||
{
|
||||
if (!bsec.getState(bsecState))
|
||||
return false;
|
||||
|
||||
Serial.println("Writing state to EEPROM");
|
||||
Serial.print("State file: ");
|
||||
|
||||
for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++)
|
||||
{
|
||||
EEPROM.write(i + 1, bsecState[i]);
|
||||
Serial.print(String(bsecState[i], HEX) + ", ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE);
|
||||
EEPROM.commit();
|
||||
|
||||
return true;
|
||||
}
|
||||
42
libraries/bsec2/extra_script.py
Normal file
42
libraries/bsec2/extra_script.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
Import('env')
|
||||
from os.path import join, realpath, exists
|
||||
|
||||
# We need the equivalent of build.mcu in Arduino board definitions.
|
||||
# For ESP this is BOARD_MCU
|
||||
cpu = env.get("BOARD_MCU")
|
||||
fpu = ""
|
||||
floatabi = ""
|
||||
|
||||
# For ESP32, all variants except original ESP32 and "S" series are riscv
|
||||
# The 'esp32c3' target can be used on all riscv ESP32 variants.
|
||||
if cpu.startswith("esp32") and not (cpu.startswith("esp32s") or cpu == "esp32"):
|
||||
cpu = "esp32c3"
|
||||
|
||||
# For ARM cores, BOARD_MCU is the chip (e.g. rp2040), not the cpu (e.g. cortex-m0plus).
|
||||
# To find the correct binary, we check the linkflags.
|
||||
linkflags = env.get("LINKFLAGS", [])
|
||||
for flag in linkflags:
|
||||
if flag.startswith("-mcpu="):
|
||||
prefix, divider, cpu = flag.partition("=")
|
||||
continue
|
||||
elif flag.startswith("-mfpu="):
|
||||
prefix, divider, fpu = flag.partition("=")
|
||||
continue
|
||||
elif flag.startswith("-mfloat-abi="):
|
||||
prefix, divider, floatabi = flag.partition("=")
|
||||
continue
|
||||
|
||||
# For M4 / M33 -- use hardfloat binaries when appropriate
|
||||
if cpu in ['cortex-m4', 'cortex-m33'] and floatabi == "hard":
|
||||
path = realpath(join("src", cpu, f"{fpu}-{floatabi}"))
|
||||
else:
|
||||
path = realpath(join("src", cpu))
|
||||
|
||||
if exists(path):
|
||||
env.Append(
|
||||
LIBPATH=[path],
|
||||
LIBS=["algobsec"]
|
||||
)
|
||||
else:
|
||||
print(f"BSEC2 is not supported for CPU '{cpu} {floatabi}', path '{path}' doesn't exist")
|
||||
exit(1)
|
||||
144
libraries/bsec2/keywords.txt
Normal file
144
libraries/bsec2/keywords.txt
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#######################################
|
||||
# BSEC2 Keywords #
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Bsec2 KEYWORD1
|
||||
Bme68x KEYWORD1
|
||||
bsecSensor KEYWORD1
|
||||
bsecData KEYWORD1
|
||||
bsecOutputs KEYWORD1
|
||||
bmeConf KEYWORD1
|
||||
version KEYWORD1
|
||||
status KEYWORD1
|
||||
opMode KEYWORD1
|
||||
extTempOffset KEYWORD1
|
||||
ovfCounter KEYWORD1
|
||||
lastMillis KEYWORD1
|
||||
bsecInstance KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
updateSubscription KEYWORD2
|
||||
run KEYWORD2
|
||||
attachCallback KEYWORD2
|
||||
getOutputs KEYWORD2
|
||||
getData KEYWORD2
|
||||
getState KEYWORD2
|
||||
setState KEYWORD2
|
||||
getConfig KEYWORD2
|
||||
setConfig KEYWORD2
|
||||
setTemperatureOffset KEYWORD2
|
||||
getTimeMs KEYWORD2
|
||||
allocateMemory KEYWORD2
|
||||
clearMemory KEYWORD2
|
||||
newDataCallback KEYWORD2
|
||||
processData KEYWORD2
|
||||
beginCommon KEYWORD2
|
||||
setBme68xConfigForced KEYWORD2
|
||||
setBme68xConfigParallel KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
sensor KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
BSEC_MAX_WORKBUFFER_SIZE LITERAL1
|
||||
BSEC_MAX_PHYSICAL_SENSOR LITERAL1
|
||||
BSEC_MAX_PROPERTY_BLOB_SIZE LITERAL1
|
||||
BSEC_MAX_STATE_BLOB_SIZE LITERAL1
|
||||
BSEC_SAMPLE_RATE_DISABLED LITERAL1
|
||||
BSEC_SAMPLE_RATE_ULP LITERAL1
|
||||
BSEC_SAMPLE_RATE_CONT LITERAL1
|
||||
BSEC_SAMPLE_RATE_LP LITERAL1
|
||||
BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND LITERAL1
|
||||
BSEC_SAMPLE_RATE_SCAN LITERAL1
|
||||
BSEC_PROCESS_PRESSURE LITERAL1
|
||||
BSEC_PROCESS_TEMPERATURE LITERAL1
|
||||
BSEC_PROCESS_HUMIDITY LITERAL1
|
||||
BSEC_PROCESS_GAS LITERAL1
|
||||
BSEC_PROCESS_PROFILE_PART LITERAL1
|
||||
BSEC_NUMBER_OUTPUTS LITERAL1
|
||||
BSEC_OUTPUT_INCLUDED LITERAL1
|
||||
|
||||
# BSEC inputs
|
||||
BSEC_INPUT_PRESSURE LITERAL1
|
||||
BSEC_INPUT_HUMIDITY LITERAL1
|
||||
BSEC_INPUT_TEMPERATURE LITERAL1
|
||||
BSEC_INPUT_GASRESISTOR LITERAL1
|
||||
BSEC_INPUT_HEATSOURCE LITERAL1
|
||||
BSEC_INPUT_DISABLE_BASELINE_TRACKER LITERAL1
|
||||
BSEC_INPUT_PROFILE_PART LITERAL1
|
||||
|
||||
# BSEC outputs
|
||||
BSEC_OUTPUT_IAQ LITERAL1
|
||||
BSEC_OUTPUT_STATIC_IAQ LITERAL1
|
||||
BSEC_OUTPUT_CO2_EQUIVALENT LITERAL1
|
||||
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT LITERAL1
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE LITERAL1
|
||||
BSEC_OUTPUT_RAW_PRESSURE LITERAL1
|
||||
BSEC_OUTPUT_RAW_HUMIDITY LITERAL1
|
||||
BSEC_OUTPUT_RAW_GAS LITERAL1
|
||||
BSEC_OUTPUT_STABILIZATION_STATUS LITERAL1
|
||||
BSEC_OUTPUT_RUN_IN_STATUS LITERAL1
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE LITERAL1
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY LITERAL1
|
||||
BSEC_OUTPUT_COMPENSATED_GAS LITERAL1
|
||||
BSEC_OUTPUT_GAS_PERCENTAGE LITERAL1
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_1 LITERAL1
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_2 LITERAL1
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_3 LITERAL1
|
||||
BSEC_OUTPUT_GAS_ESTIMATE_4 LITERAL1
|
||||
BSEC_OUTPUT_RAW_GAS_INDEX LITERAL1
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_1 LITERAL1
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_2 LITERAL1
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_3 LITERAL1
|
||||
BSEC_OUTPUT_REGRESSION_ESTIMATE_4 LITERAL1
|
||||
|
||||
# BSEC return codes
|
||||
BSEC_OK LITERAL1
|
||||
BSEC_E_DOSTEPS_INVALIDINPUT LITERAL1
|
||||
BSEC_E_DOSTEPS_VALUELIMITS LITERAL1
|
||||
BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE LITERAL1
|
||||
BSEC_E_DOSTEPS_DUPLICATEINPUT LITERAL1
|
||||
BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE LITERAL1
|
||||
BSEC_W_DOSTEPS_EXCESSOUTPUTS LITERAL1
|
||||
BSEC_W_DOSTEPS_GASINDEXMISS LITERAL1
|
||||
BSEC_E_SU_WRONGDATARATE LITERAL1
|
||||
BSEC_E_SU_SAMPLERATELIMITS LITERAL1
|
||||
BSEC_E_SU_DUPLICATEGATE LITERAL1
|
||||
BSEC_E_SU_INVALIDSAMPLERATE LITERAL1
|
||||
BSEC_E_SU_GATECOUNTEXCEEDSARRAY LITERAL1
|
||||
BSEC_E_SU_SAMPLINTVLINTEGERMULT LITERAL1
|
||||
BSEC_E_SU_MULTGASSAMPLINTVL LITERAL1
|
||||
BSEC_E_SU_HIGHHEATERONDURATION LITERAL1
|
||||
BSEC_W_SU_UNKNOWNOUTPUTGATE LITERAL1
|
||||
BSEC_W_SU_MODINNOULP LITERAL1
|
||||
BSEC_I_SU_SUBSCRIBEDOUTPUTGATES LITERAL1
|
||||
BSEC_I_SU_GASESTIMATEPRECEDENCE LITERAL1
|
||||
BSEC_W_SU_SAMPLERATEMISMATCH LITERAL1
|
||||
BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER LITERAL1
|
||||
BSEC_E_CONFIG_FAIL LITERAL1
|
||||
BSEC_E_CONFIG_VERSIONMISMATCH LITERAL1
|
||||
BSEC_E_CONFIG_FEATUREMISMATCH LITERAL1
|
||||
BSEC_E_CONFIG_CRCMISMATCH LITERAL1
|
||||
BSEC_E_CONFIG_EMPTY LITERAL1
|
||||
BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER LITERAL1
|
||||
BSEC_E_CONFIG_INVALIDSTRINGSIZE LITERAL1
|
||||
BSEC_E_CONFIG_INSUFFICIENTBUFFER LITERAL1
|
||||
BSEC_E_SET_INVALIDCHANNELIDENTIFIER LITERAL1
|
||||
BSEC_E_SET_INVALIDLENGTH LITERAL1
|
||||
BSEC_W_SC_CALL_TIMING_VIOLATION LITERAL1
|
||||
BSEC_W_SC_MODEXCEEDULPTIMELIMIT LITERAL1
|
||||
BSEC_W_SC_MODINSUFFICIENTWAITTIME LITERAL1
|
||||
47
libraries/bsec2/library.json
Normal file
47
libraries/bsec2/library.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "bsec2",
|
||||
"description": "Bosch Sensortec Environmental Cluster (BSEC) Software library for use with the BME68x has been conceptualized to provide higher-level signal processing and fusion for the BME68x. The library receives compensated sensor values from the sensor API. It processes the BME68x signals to provide the requested sensor outputs.",
|
||||
"homepage": "https://www.bosch-sensortec.com/software-tools/software/bme688-software/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/boschsensortec/Bosch-BSEC2-Library"
|
||||
},
|
||||
"version": "1.10.2610",
|
||||
"authors": {
|
||||
"name": "Bosch Sensortec",
|
||||
"email": "contact@bosch-sensortec.com"
|
||||
},
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
"build": {
|
||||
"includeDir": "src/inc",
|
||||
"extraScript": "extra_script.py"
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"name": "Basic usage for Adafruit ESP8266 Board",
|
||||
"base": "examples/generic_examples/basic",
|
||||
"files": ["basic.ino"]
|
||||
},
|
||||
{
|
||||
"name": "Basic usage with config state saves for Adafruit ESP8266 Board",
|
||||
"base": "examples/generic_examples/basic_config_state",
|
||||
"files": ["basic_config_state.ino"]
|
||||
},
|
||||
{
|
||||
"name": "Basic usage for Adafruit ESP32 Feather Board",
|
||||
"base": "examples/x8_board_examples/basic",
|
||||
"files": ["basic.ino"]
|
||||
},
|
||||
{
|
||||
"name": "Basic usage with config state saves for Adafruit ESP32 Feather Board",
|
||||
"base": "examples/x8_board_examples/basic_config_state",
|
||||
"files": ["basic_config_state.ino"]
|
||||
},
|
||||
{
|
||||
"name": "datalogging and integration of BSEC2x library for Adafruit ESP32 Feather Board",
|
||||
"base": "examples/bme68x_demo_sample",
|
||||
"files": ["bme68x_demo_sample.ino"]
|
||||
}
|
||||
]
|
||||
}
|
||||
13
libraries/bsec2/library.properties
Normal file
13
libraries/bsec2/library.properties
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
name=bsec2
|
||||
version=1.10.2610
|
||||
author=Bosch Sensortec
|
||||
maintainer=Bosch Sensortec <contact@bosch-sensortec.com>
|
||||
sentence=Bosch Sensortec Environmental Cluster (BSEC) Software library
|
||||
url=https://www.bosch-sensortec.com/software-tools/software/bme688-software/
|
||||
paragraph=for use with the BME68x has been conceptualized to provide higher-level signal processing and fusion for the BME68x. The library receives compensated sensor values from the sensor API. It processes the BME68x signals to provide the requested sensor outputs.
|
||||
category=Sensors
|
||||
architectures=samd,sam,esp8266,esp32,esp32s2,esp32s3,esp32c3,mbed,nrf52
|
||||
includes=bsec2.h
|
||||
precompiled=true
|
||||
ldflags=-lalgobsec
|
||||
depends=BME68x Sensor library
|
||||
464
libraries/bsec2/src/bsec2.cpp
Normal file
464
libraries/bsec2/src/bsec2.cpp
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
/**
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bsec2.cpp
|
||||
* @date 18 July 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bsec2.h"
|
||||
|
||||
static uint8_t workBuffer[BSEC_MAX_WORKBUFFER_SIZE];
|
||||
|
||||
/**
|
||||
* @brief Constructor of Bsec2 class
|
||||
*/
|
||||
Bsec2::Bsec2(void)
|
||||
{
|
||||
ovfCounter = 0;
|
||||
lastMillis = 0;
|
||||
status = BSEC_OK;
|
||||
extTempOffset = 0.0f;
|
||||
opMode = BME68X_SLEEP_MODE;
|
||||
newDataCallback = nullptr;
|
||||
bsecInstance = nullptr;
|
||||
|
||||
memset(&version, 0, sizeof(version));
|
||||
memset(&bmeConf, 0, sizeof(bmeConf));
|
||||
memset(&outputs, 0, sizeof(outputs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on custom callbacks
|
||||
*/
|
||||
bool Bsec2::begin(bme68xIntf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write,
|
||||
bme68x_delay_us_fptr_t idleTask, void *intfPtr, unsigned long (*millis)())
|
||||
{
|
||||
bsecMillis = millis;
|
||||
sensor.begin(intf, read, write, idleTask, intfPtr);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return false;
|
||||
|
||||
return beginCommon();
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on custom callbacks
|
||||
*/
|
||||
bool Bsec2::begin(bme68xIntf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write,
|
||||
bme68x_delay_us_fptr_t idleTask, void *intfPtr)
|
||||
{
|
||||
bsecMillis = millis;
|
||||
sensor.begin(intf, read, write, idleTask, intfPtr);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return false;
|
||||
|
||||
return beginCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on the Wire library
|
||||
*/
|
||||
bool Bsec2::begin(uint8_t i2cAddr, TwoWire &i2c, bme68x_delay_us_fptr_t idleTask)
|
||||
{
|
||||
bsecMillis = millis;
|
||||
sensor.begin(i2cAddr, i2c, idleTask);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return false;
|
||||
|
||||
return beginCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on the SPI library
|
||||
*/
|
||||
bool Bsec2::begin(uint8_t chipSelect, SPIClass &spi, bme68x_delay_us_fptr_t idleTask)
|
||||
{
|
||||
bsecMillis = millis;
|
||||
sensor.begin(chipSelect, spi, idleTask);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return false;
|
||||
|
||||
return beginCommon();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Function to request/subscribe for desired virtual outputs with the supported sample rates
|
||||
*/
|
||||
bool Bsec2::updateSubscription(bsecSensor sensorList[], uint8_t nSensors, float sampleRate)
|
||||
{
|
||||
bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS], sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
|
||||
uint8_t nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
|
||||
|
||||
for (uint8_t i = 0; i < nSensors; i++)
|
||||
{
|
||||
virtualSensors[i].sensor_id = sensorList[i];
|
||||
virtualSensors[i].sample_rate = sampleRate;
|
||||
}
|
||||
|
||||
/* Subscribe to library virtual sensors outputs */
|
||||
status = bsec_update_subscription_m(bsecInstance, virtualSensors, nSensors, sensorSettings, &nSensorSettings);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback from the user to read data from the BME68X using parallel mode/forced mode, process and store outputs
|
||||
*/
|
||||
bool Bsec2::run(void)
|
||||
{
|
||||
uint8_t nFieldsLeft = 0;
|
||||
bme68xData data;
|
||||
int64_t currTimeNs = getTimeMs() * INT64_C(1000000);
|
||||
opMode = bmeConf.op_mode;
|
||||
|
||||
if (currTimeNs >= bmeConf.next_call)
|
||||
{
|
||||
/* Provides the information about the current sensor configuration that is
|
||||
necessary to fulfill the input requirements, eg: operation mode, timestamp
|
||||
at which the sensor data shall be fetched etc */
|
||||
status = bsec_sensor_control_m(bsecInstance ,currTimeNs, &bmeConf);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
switch (bmeConf.op_mode)
|
||||
{
|
||||
case BME68X_FORCED_MODE:
|
||||
setBme68xConfigForced();
|
||||
break;
|
||||
case BME68X_PARALLEL_MODE:
|
||||
if (opMode != bmeConf.op_mode)
|
||||
{
|
||||
setBme68xConfigParallel();
|
||||
}
|
||||
break;
|
||||
|
||||
case BME68X_SLEEP_MODE:
|
||||
if (opMode != bmeConf.op_mode)
|
||||
{
|
||||
sensor.setOpMode(BME68X_SLEEP_MODE);
|
||||
opMode = BME68X_SLEEP_MODE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return false;
|
||||
|
||||
if (bmeConf.trigger_measurement && bmeConf.op_mode != BME68X_SLEEP_MODE)
|
||||
{
|
||||
if (sensor.fetchData())
|
||||
{
|
||||
do
|
||||
{
|
||||
nFieldsLeft = sensor.getData(data);
|
||||
/* check for valid gas data */
|
||||
if (data.status & BME68X_GASM_VALID_MSK)
|
||||
{
|
||||
/* Convert sensor raw pressure unit from pascal to hecto pascal */
|
||||
data.pressure *= 0.01f;
|
||||
|
||||
if (!processData(currTimeNs, data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (nFieldsLeft);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the state of the algorithm to save to non-volatile memory
|
||||
*/
|
||||
bool Bsec2::getState(uint8_t *state)
|
||||
{
|
||||
uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
|
||||
|
||||
status = bsec_get_state_m(bsecInstance, 0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_WORKBUFFER_SIZE,
|
||||
&n_serialized_state);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to set the state of the algorithm from non-volatile memory
|
||||
*/
|
||||
bool Bsec2::setState(uint8_t *state)
|
||||
{
|
||||
status = bsec_set_state_m(bsecInstance, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer, BSEC_MAX_WORKBUFFER_SIZE);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
memset(&bmeConf, 0, sizeof(bmeConf));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to retrieve the current library configuration
|
||||
*/
|
||||
bool Bsec2::getConfig(uint8_t *config)
|
||||
{
|
||||
uint32_t n_serialized_settings = 0;
|
||||
|
||||
status = bsec_get_configuration_m(bsecInstance, 0, config, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, BSEC_MAX_WORKBUFFER_SIZE, &n_serialized_settings);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to set the configuration of the algorithm from memory
|
||||
*/
|
||||
bool Bsec2::setConfig(const uint8_t *config)
|
||||
{
|
||||
status = bsec_set_configuration_m(bsecInstance, config, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, BSEC_MAX_WORKBUFFER_SIZE);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
memset(&bmeConf, 0, sizeof(bmeConf));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||
*/
|
||||
int64_t Bsec2::getTimeMs(void)
|
||||
{
|
||||
int64_t timeMs = bsecMillis();
|
||||
|
||||
if (lastMillis > timeMs) /* An overflow occurred */
|
||||
{
|
||||
ovfCounter++;
|
||||
}
|
||||
|
||||
lastMillis = timeMs;
|
||||
|
||||
return timeMs + (ovfCounter * INT64_C(0xFFFFFFFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to assign the memory block to the bsec instance
|
||||
*/
|
||||
void Bsec2::allocateMemory(uint8_t (&memBlock)[BSEC_INSTANCE_SIZE])
|
||||
{
|
||||
/* allocating memory for the bsec instance */
|
||||
bsecInstance = memBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to de-allocate the dynamically allocated memory
|
||||
*/
|
||||
void Bsec2::clearMemory(void)
|
||||
{
|
||||
delete[] bsecInstance;
|
||||
}
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/**
|
||||
* @brief Reads data from the BME68X sensor and process it
|
||||
*/
|
||||
bool Bsec2::processData(int64_t currTimeNs, const bme68xData &data)
|
||||
{
|
||||
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; /* Temp, Pres, Hum & Gas */
|
||||
uint8_t nInputs = 0;
|
||||
/* Checks all the required sensor inputs, required for the BSEC library for the requested outputs */
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_HEATSOURCE))
|
||||
{
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
|
||||
inputs[nInputs].signal = extTempOffset;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_TEMPERATURE))
|
||||
{
|
||||
#ifdef BME68X_USE_FPU
|
||||
inputs[nInputs].signal = data.temperature;
|
||||
#else
|
||||
inputs[nInputs].signal = data.temperature / 100.0f;
|
||||
#endif
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_HUMIDITY))
|
||||
{
|
||||
#ifdef BME68X_USE_FPU
|
||||
inputs[nInputs].signal = data.humidity;
|
||||
#else
|
||||
inputs[nInputs].signal = data.humidity / 1000.0f;
|
||||
#endif
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_PRESSURE))
|
||||
{
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
|
||||
inputs[nInputs].signal = data.pressure;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_GASRESISTOR) &&
|
||||
(data.status & BME68X_GASM_VALID_MSK))
|
||||
{
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
|
||||
inputs[nInputs].signal = data.gas_resistance;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (BSEC_CHECK_INPUT(bmeConf.process_data, BSEC_INPUT_PROFILE_PART) &&
|
||||
(data.status & BME68X_GASM_VALID_MSK))
|
||||
{
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_PROFILE_PART;
|
||||
inputs[nInputs].signal = (opMode == BME68X_FORCED_MODE) ? 0 : data.gas_index;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
|
||||
if (nInputs > 0)
|
||||
{
|
||||
|
||||
outputs.nOutputs = BSEC_NUMBER_OUTPUTS;
|
||||
memset(outputs.output, 0, sizeof(outputs.output));
|
||||
|
||||
/* Processing of the input signals and returning of output samples is performed by bsec_do_steps() */
|
||||
status = bsec_do_steps_m(bsecInstance, inputs, nInputs, outputs.output, &outputs.nOutputs);
|
||||
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
if(newDataCallback)
|
||||
newDataCallback(data, outputs, *this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common code for the begin function
|
||||
*/
|
||||
bool Bsec2::beginCommon()
|
||||
{
|
||||
if (!bsecInstance)
|
||||
{
|
||||
/* allocate memory for the instance if not allocated */
|
||||
bsecInstance = new uint8_t[bsec_get_instance_size_m()];
|
||||
}
|
||||
|
||||
if (BSEC_INSTANCE_SIZE < bsec_get_instance_size_m())
|
||||
{
|
||||
status = BSEC_E_INSUFFICIENT_INSTANCE_SIZE;
|
||||
return false;
|
||||
}
|
||||
status = bsec_init_m(bsecInstance);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
status = bsec_get_version_m(bsecInstance, &version);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
memset(&bmeConf, 0, sizeof(bmeConf));
|
||||
memset(&outputs, 0, sizeof(outputs));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BME68X sensor configuration to forced mode
|
||||
*/
|
||||
void Bsec2::setBme68xConfigForced(void)
|
||||
{
|
||||
/* Set the filter, odr, temperature, pressure and humidity settings */
|
||||
sensor.setTPH(bmeConf.temperature_oversampling, bmeConf.pressure_oversampling, bmeConf.humidity_oversampling);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
sensor.setHeaterProf(bmeConf.heater_temperature, bmeConf.heater_duration);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
sensor.setOpMode(BME68X_FORCED_MODE);
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
opMode = BME68X_FORCED_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BME68X sensor configuration to parallel mode
|
||||
*/
|
||||
void Bsec2::setBme68xConfigParallel(void)
|
||||
{
|
||||
uint16_t sharedHeaterDur = 0;
|
||||
|
||||
/* Set the filter, odr, temperature, pressure and humidity settings */
|
||||
sensor.setTPH(bmeConf.temperature_oversampling, bmeConf.pressure_oversampling, bmeConf.humidity_oversampling);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
sharedHeaterDur = BSEC_TOTAL_HEAT_DUR - (sensor.getMeasDur(BME68X_PARALLEL_MODE) / INT64_C(1000));
|
||||
|
||||
sensor.setHeaterProf(bmeConf.heater_temperature_profile, bmeConf.heater_duration_profile, sharedHeaterDur,
|
||||
bmeConf.heater_profile_len);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
sensor.setOpMode(BME68X_PARALLEL_MODE);
|
||||
|
||||
if (sensor.checkStatus() == BME68X_ERROR)
|
||||
return;
|
||||
|
||||
opMode = BME68X_PARALLEL_MODE;
|
||||
}
|
||||
282
libraries/bsec2/src/bsec2.h
Normal file
282
libraries/bsec2/src/bsec2.h
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/**
|
||||
* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
*
|
||||
* BSD-3-Clause
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file bsec2.h
|
||||
* @date 18 July 2024
|
||||
* @version 2.1.5
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSEC2_H_
|
||||
#define BSEC2_H_
|
||||
|
||||
/* Includes */
|
||||
#ifdef ARDUINO
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
#include "SPI.h"
|
||||
#endif
|
||||
|
||||
/* dependent library header */
|
||||
#include "bme68xLibrary.h"
|
||||
#include "inc/bsec_datatypes.h"
|
||||
#include "inc/bsec_interface_multi.h"
|
||||
|
||||
#ifndef ARRAY_LEN
|
||||
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
|
||||
#endif
|
||||
|
||||
#define BSEC_CHECK_INPUT(x, shift) (x & (1 << (shift-1)))
|
||||
#define BSEC_TOTAL_HEAT_DUR UINT16_C(140)
|
||||
#define BSEC_INSTANCE_SIZE 3272
|
||||
#define BSEC_E_INSUFFICIENT_INSTANCE_SIZE (bsec_library_return_t)-105
|
||||
|
||||
/*
|
||||
* The default offset provided has been determined by testing the sensor in LP and ULP mode on application board 3.0
|
||||
* Please update the offset value after testing this on your product
|
||||
*/
|
||||
#define TEMP_OFFSET_LP (1.3255f)
|
||||
#define TEMP_OFFSET_ULP (0.466f)
|
||||
|
||||
typedef bsec_output_t bsecData;
|
||||
typedef bsec_virtual_sensor_t bsecSensor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bsecData output[BSEC_NUMBER_OUTPUTS];
|
||||
uint8_t nOutputs;
|
||||
} bsecOutputs;
|
||||
|
||||
class Bsec2;
|
||||
typedef void (*bsecCallback)(const bme68xData data, const bsecOutputs outputs, const Bsec2 bsec);
|
||||
|
||||
/* BSEC2 class definition */
|
||||
class Bsec2
|
||||
{
|
||||
public:
|
||||
Bme68x sensor;
|
||||
/* Stores the version of the BSEC algorithm */
|
||||
bsec_version_t version;
|
||||
bsec_library_return_t status;
|
||||
|
||||
Bsec2(void);
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on custom callbacks
|
||||
* @param intf : BME68X_SPI_INTF or BME68X_I2C_INTF interface
|
||||
* @param read : Read callback
|
||||
* @param write : Write callback
|
||||
* @param idleTask : Delay or Idle function
|
||||
* @param millis : Function to get current time in milliseconds
|
||||
* @param intfPtr : Pointer to the interface descriptor
|
||||
* @return True if everything initialized correctly
|
||||
*/
|
||||
bool begin(bme68xIntf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write,
|
||||
bme68x_delay_us_fptr_t idleTask, void *intfPtr, unsigned long (*millis)());
|
||||
|
||||
#ifdef ARDUINO
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on custom callbacks
|
||||
* @param intf : BME68X_SPI_INTF or BME68X_I2C_INTF interface
|
||||
* @param read : Read callback
|
||||
* @param write : Write callback
|
||||
* @param idleTask : Delay or Idle function
|
||||
* @param intfPtr : Pointer to the interface descriptor
|
||||
* @return True if everything initialized correctly
|
||||
*/
|
||||
bool begin(bme68xIntf intf, bme68x_read_fptr_t read, bme68x_write_fptr_t write,
|
||||
bme68x_delay_us_fptr_t idleTask, void *intfPtr);
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on the Wire library
|
||||
* @param i2cAddr : The I2C address the sensor is at
|
||||
* @param i2c : The TwoWire object
|
||||
* @param idleTask : Delay or Idle function
|
||||
* @return True if everything initialized correctly
|
||||
*/
|
||||
bool begin(uint8_t i2cAddr, TwoWire &i2c, bme68x_delay_us_fptr_t idleTask = bme68xDelayUs);
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the sensor based on the SPI library
|
||||
* @param chipSelect : The chip select pin for SPI communication
|
||||
* @param spi : The SPIClass object
|
||||
* @param idleTask : Delay or Idle function
|
||||
* @return True if everything initialized correctly
|
||||
*/
|
||||
bool begin(uint8_t chipSelect, SPIClass &spi, bme68x_delay_us_fptr_t idleTask = bme68xDelayUs);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool updateSubscription(bsecSensor sensorList[], uint8_t nSensors, float sampleRate =
|
||||
BSEC_SAMPLE_RATE_ULP);
|
||||
|
||||
/**
|
||||
* @brief Callback from the user to read data from the BME68x using parallel/forced mode, process and store outputs
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool run(void);
|
||||
|
||||
void attachCallback(bsecCallback callback)
|
||||
{
|
||||
newDataCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the BSEC outputs
|
||||
* @return pointer to BSEC outputs if available else nullptr
|
||||
*/
|
||||
const bsecOutputs* getOutputs(void)
|
||||
{
|
||||
if (outputs.nOutputs)
|
||||
return &outputs;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the BSEC output by sensor id
|
||||
* @return pointer to BSEC output, nullptr otherwise
|
||||
*/
|
||||
bsecData getData(bsecSensor id)
|
||||
{
|
||||
bsecData emp;
|
||||
memset(&emp, 0, sizeof(emp));
|
||||
for (uint8_t i = 0; i < outputs.nOutputs; i++)
|
||||
if (id == outputs.output[i].sensor_id)
|
||||
return outputs.output[i];
|
||||
return emp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the state of the algorithm to save to non-volatile memory
|
||||
* @param state : Pointer to a memory location, to hold the state
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool 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
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool setState(uint8_t *state);
|
||||
|
||||
/**
|
||||
* @brief Function to retrieve the current library configuration
|
||||
* @param config : Pointer to a memory location, to hold the serialized config blob
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool getConfig(uint8_t *config);
|
||||
|
||||
/**
|
||||
* @brief Function to set the configuration of the algorithm from memory
|
||||
* @param state : Pointer to a memory location that contains the configuration
|
||||
* @return true for success, false otherwise
|
||||
*/
|
||||
bool setConfig(const uint8_t *config);
|
||||
|
||||
/**
|
||||
* @brief Function to set the temperature offset
|
||||
* @param tempOffset : Temperature offset in degree Celsius
|
||||
*/
|
||||
void setTemperatureOffset(float tempOffset)
|
||||
{
|
||||
extTempOffset = tempOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||
*/
|
||||
int64_t getTimeMs(void);
|
||||
|
||||
/**
|
||||
* @brief Function to assign the memory block to the bsec instance
|
||||
*
|
||||
* @param[in] memBlock : reference to the memory block
|
||||
*/
|
||||
void allocateMemory(uint8_t (&memBlock)[BSEC_INSTANCE_SIZE]);
|
||||
|
||||
/**
|
||||
* @brief Function to de-allocate the dynamically allocated memory
|
||||
*/
|
||||
void clearMemory(void);
|
||||
|
||||
private:
|
||||
bsec_bme_settings_t bmeConf;
|
||||
|
||||
bsecCallback newDataCallback;
|
||||
|
||||
bsecOutputs outputs;
|
||||
/* operating mode of sensor */
|
||||
uint8_t opMode;
|
||||
|
||||
float extTempOffset;
|
||||
/** 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 ovfCounter;
|
||||
|
||||
unsigned long (*bsecMillis)();
|
||||
|
||||
uint32_t lastMillis;
|
||||
/* Pointer to hold the address of the instance */
|
||||
uint8_t *bsecInstance;
|
||||
|
||||
/**
|
||||
* @brief Reads the data from the BME68x sensor and process it
|
||||
* @param currTimeNs: Current time in ns
|
||||
* @return true if there are new outputs. false otherwise
|
||||
*/
|
||||
bool processData(int64_t currTimeNs, const bme68xData &data);
|
||||
|
||||
/**
|
||||
* @brief Common code for the begin function
|
||||
*/
|
||||
bool beginCommon();
|
||||
|
||||
/**
|
||||
* @brief Set the BME68x sensor configuration to forced mode
|
||||
*/
|
||||
void setBme68xConfigForced(void);
|
||||
|
||||
/**
|
||||
* @brief Set the BME68x sensor configuration to parallel mode
|
||||
*/
|
||||
void setBme68xConfigParallel(void);
|
||||
};
|
||||
|
||||
#endif /* BSEC2_CLASS_H */
|
||||
158
libraries/bsec2/src/commMux/commMux.cpp
Normal file
158
libraries/bsec2/src/commMux/commMux.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
|
||||
BSD-3-Clause
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@file commMux.cpp
|
||||
@date 18 Jul 2024
|
||||
@version 2.1.5
|
||||
|
||||
*/
|
||||
#ifdef ARDUINO
|
||||
#include "commMux.h"
|
||||
|
||||
#define CLOCK_FREQUENCY UINT32_C(400000)
|
||||
#define COMM_SPEED UINT32_C(8000000)
|
||||
|
||||
const uint8_t I2C_EXPANDER_ADDR = 0x20;
|
||||
const uint8_t I2C_EXPANDER_OUTPUT_REG_ADDR = 0x01;
|
||||
const uint8_t I2C_EXPANDER_OUTPUT_DESELECT = 0xFF;
|
||||
const uint8_t I2C_EXPANDER_CONFIG_REG_ADDR = 0x03;
|
||||
const uint8_t I2C_EXPANDER_CONFIG_REG_MASK = 0x00;
|
||||
|
||||
/**
|
||||
* @brief Function to configure the communication across sensors
|
||||
*/
|
||||
comm_mux comm_mux_set_config(TwoWire &wireobj, SPIClass &spiobj, uint8_t idx, comm_mux &comm)
|
||||
{
|
||||
comm.select = ((0x01 << idx) ^ 0xFF);
|
||||
comm.spiobj = &spiobj;
|
||||
comm.wireobj = &wireobj;
|
||||
|
||||
return comm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to trigger the communication
|
||||
*/
|
||||
void comm_mux_begin(TwoWire &wireobj, SPIClass &spiobj)
|
||||
{
|
||||
wireobj.begin();
|
||||
wireobj.setClock(CLOCK_FREQUENCY);
|
||||
wireobj.beginTransmission(I2C_EXPANDER_ADDR);
|
||||
wireobj.write(I2C_EXPANDER_CONFIG_REG_ADDR);
|
||||
wireobj.write(I2C_EXPANDER_CONFIG_REG_MASK);
|
||||
wireobj.endTransmission();
|
||||
|
||||
spiobj.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to set the ship select pin of the SPI
|
||||
*/
|
||||
static void set_chip_select(TwoWire *wireobj, uint8_t mask)
|
||||
{
|
||||
// send I2C-Expander device address
|
||||
wireobj->beginTransmission(I2C_EXPANDER_ADDR);
|
||||
// send I2C-Expander output register address
|
||||
wireobj->write(I2C_EXPANDER_OUTPUT_REG_ADDR);
|
||||
// send mask to set output level of GPIO pins
|
||||
wireobj->write(mask);
|
||||
// end communication
|
||||
wireobj->endTransmission();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to write the sensor data to the register
|
||||
*/
|
||||
int8_t comm_mux_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr)
|
||||
{
|
||||
comm_mux *comm = (comm_mux*) intf_ptr;
|
||||
uint32_t i = 0;
|
||||
|
||||
if (comm)
|
||||
{
|
||||
set_chip_select(comm->wireobj, comm->select);
|
||||
|
||||
comm->spiobj->beginTransaction(SPISettings(COMM_SPEED, MSBFIRST, SPI_MODE0));
|
||||
comm->spiobj->transfer(reg_addr);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
comm->spiobj->transfer(reg_data[i]);
|
||||
}
|
||||
comm->spiobj->endTransaction();
|
||||
|
||||
set_chip_select(comm->wireobj, I2C_EXPANDER_OUTPUT_DESELECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to read the sensor data from the register
|
||||
*/
|
||||
int8_t comm_mux_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr)
|
||||
{
|
||||
comm_mux *comm = (comm_mux*) intf_ptr;
|
||||
uint32_t i = 0;
|
||||
|
||||
if (comm)
|
||||
{
|
||||
set_chip_select(comm->wireobj, comm->select);
|
||||
|
||||
comm->spiobj->beginTransaction(SPISettings(COMM_SPEED, MSBFIRST, SPI_MODE0));
|
||||
comm->spiobj->transfer(reg_addr);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
reg_data[i] = comm->spiobj->transfer(0xFF);
|
||||
}
|
||||
comm->spiobj->endTransaction();
|
||||
|
||||
set_chip_select(comm->wireobj, I2C_EXPANDER_OUTPUT_DESELECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to maintain a delay between communication
|
||||
*/
|
||||
void comm_mux_delay(uint32_t period_us, void *intf_ptr)
|
||||
{
|
||||
(void) intf_ptr;
|
||||
delayMicroseconds(period_us);
|
||||
}
|
||||
#endif
|
||||
100
libraries/bsec2/src/commMux/commMux.h
Normal file
100
libraries/bsec2/src/commMux/commMux.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
|
||||
|
||||
BSD-3-Clause
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@file commMux.h
|
||||
@date 18 Jul 2024
|
||||
@version 2.1.5
|
||||
|
||||
*/
|
||||
#ifdef ARDUINO
|
||||
#ifndef COMM_MUX_H
|
||||
#define COMM_MUX_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
#include "SPI.h"
|
||||
|
||||
/**
|
||||
* Datatype working as an interface descriptor
|
||||
*/
|
||||
typedef struct {
|
||||
TwoWire *wireobj;
|
||||
SPIClass *spiobj;
|
||||
uint8_t select;
|
||||
} comm_mux;
|
||||
|
||||
/**
|
||||
* @brief Function to configure the communication across sensors
|
||||
* @param wireobj : The TwoWire object
|
||||
* @param spiobj : The SPIClass object
|
||||
* @param idx : Selected sensor for communication interface
|
||||
* @param comm : Structure for selected sensor
|
||||
* @return : Structure holding the communication setup
|
||||
*/
|
||||
comm_mux comm_mux_set_config(TwoWire &wireobj, SPIClass &spiobj, uint8_t idx, comm_mux &comm);
|
||||
|
||||
/**
|
||||
* @brief Function to trigger the communication
|
||||
* @param wireobj : The TwoWire object
|
||||
* @param spiobj : The SPIClass object
|
||||
*/
|
||||
void comm_mux_begin(TwoWire &wireobj, SPIClass &spiobj);
|
||||
|
||||
/**
|
||||
* @brief Function to write the sensor data to the register
|
||||
* @param reg_addr : Address of the register
|
||||
* @param reg_data : Pointer to the data to be written
|
||||
* @param length : length of the register data
|
||||
* @param intf_ptr : Pointer to the interface descriptor
|
||||
* @return 0 if successful, non-zero otherwise
|
||||
*/
|
||||
int8_t comm_mux_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr);
|
||||
|
||||
/**
|
||||
* @brief Function to read the sensor data from the register
|
||||
* @param reg_addr : Address of the register
|
||||
* @param reg_data : Pointer to the data to be read from the sensor
|
||||
* @param length : length of the register data
|
||||
* @param intf_ptr : Pointer to the interface descriptor
|
||||
* @return 0 if successful, non-zero otherwise
|
||||
*/
|
||||
int8_t comm_mux_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr);
|
||||
|
||||
/**
|
||||
* @brief Function to maintain a delay between communication
|
||||
* @param period_us : Time delay in micro secs
|
||||
* @param intf_ptr : Pointer to the interface descriptor
|
||||
*/
|
||||
void comm_mux_delay(uint32_t period_us, void *intf_ptr);
|
||||
|
||||
#endif /* COMM_MUX_H */
|
||||
#endif
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
libraries/bsec2/src/cortex-m0plus/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m0plus/libalgobsec.a
Normal file
Binary file not shown.
2
libraries/bsec2/src/cortex-m0plus/libalgobsec.a.size.log
Normal file
2
libraries/bsec2/src/cortex-m0plus/libalgobsec.a.size.log
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
text data bss dec hex filename
|
||||
34849 0 3888 38737 9751 (TOTALS)
|
||||
BIN
libraries/bsec2/src/cortex-m3/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m3/libalgobsec.a
Normal file
Binary file not shown.
2
libraries/bsec2/src/cortex-m3/libalgobsec.a.size.log
Normal file
2
libraries/bsec2/src/cortex-m3/libalgobsec.a.size.log
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
text data bss dec hex filename
|
||||
31677 0 3888 35565 8aed (TOTALS)
|
||||
BIN
libraries/bsec2/src/cortex-m33/fpv5-sp-d16-hard/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m33/fpv5-sp-d16-hard/libalgobsec.a
Normal file
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
text data bss dec hex filename
|
||||
32254 0 3888 36142 8d2e (TOTALS)
|
||||
BIN
libraries/bsec2/src/cortex-m33/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m33/libalgobsec.a
Normal file
Binary file not shown.
2
libraries/bsec2/src/cortex-m33/libalgobsec.a.Size.log
Normal file
2
libraries/bsec2/src/cortex-m33/libalgobsec.a.Size.log
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
text data bss dec hex filename
|
||||
31697 0 3888 35585 8b01 (TOTALS)
|
||||
BIN
libraries/bsec2/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m4/fpv4-sp-d16-hard/libalgobsec.a
Normal file
Binary file not shown.
|
|
@ -0,0 +1,2 @@
|
|||
text data bss dec hex filename
|
||||
32390 0 3888 36278 8db6 (TOTALS)
|
||||
BIN
libraries/bsec2/src/cortex-m4/libalgobsec.a
Normal file
BIN
libraries/bsec2/src/cortex-m4/libalgobsec.a
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue