commit
dc90681cde
@ -3,7 +3,7 @@
|
||||
|
||||
Tutorial (in german language): https://www.heise.de/select/make/2019/1/1551099236518668
|
||||
|
||||
**#36C3 attendees: i am on site (27th - 30th)! You might contact me via twitter @RecumbentTravel**
|
||||
|
||||
|
||||
<img src="img/Paxcounter-title.jpg">
|
||||
<img src="img/Paxcounter-ttgo.jpg">
|
||||
@ -33,12 +33,15 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
||||
*LoRa & SPI*:
|
||||
|
||||
- Heltec: LoRa-32 v1 and v2
|
||||
- TTGO: T1*, T2*, T3*, T-Beam, T-Fox (* supports microSD-card)
|
||||
- TTGO: T1*, T2*, T3*, T-Beam, T-Fox
|
||||
- Pycom: LoPy, LoPy4, FiPy
|
||||
- Radioshuttle.de: [ECO Power Board](https://www.radioshuttle.de/esp32-eco-power/esp32-eco-power-board/)
|
||||
- WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora),
|
||||
LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
|
||||
- Adafruit ESP32 Feather + LoRa Wing + OLED Wing, #IoT Octopus32 (Octopus + ESP32 Feather)
|
||||
- M5Stack: [Basic Core IoT*](https://m5stack.com/collections/m5-core/products/basic-core-iot-development-kit) + [Lora Module RA-01H](https://m5stack.com/collections/m5-module/products/lora-module-868mhz), [Fire IoT*](https://m5stack.com/collections/m5-core/products/fire-iot-development-kit)
|
||||
|
||||
*) supports microSD-card
|
||||
|
||||
*SPI only*:
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <Wire.h>
|
||||
|
||||
#ifdef HAS_BME680
|
||||
#include "../lib/Bosch-BSEC/src/bsec.h"
|
||||
#include <bsec.h>
|
||||
#elif defined HAS_BME280
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
|
@ -9,7 +9,7 @@ extern uint8_t DisplayIsOn, displaybuf[];
|
||||
void refreshTheDisplay(bool nextPage = false);
|
||||
void init_display(bool verbose = false);
|
||||
void shutdown_display(void);
|
||||
void draw_page(time_t t, uint8_t page);
|
||||
void draw_page(time_t t, bool nextpage);
|
||||
void dp_printf(uint16_t x, uint16_t y, uint8_t font, uint8_t inv,
|
||||
const char *format, ...);
|
||||
void dp_printqr(uint16_t offset_x, uint16_t offset_y, const char *Message);
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include "mallocator.h"
|
||||
#include "../lib/Bosch-BSEC/src/inc/bsec_datatypes.h"
|
||||
#include <bsec.h>
|
||||
|
||||
// sniffing types
|
||||
#define MAC_SNIFF_WIFI 0
|
||||
|
@ -28,6 +28,8 @@ licenses. Refer to LICENSE.txt file in repository for more details.
|
||||
|
||||
esp_err_t spi_init();
|
||||
|
||||
extern TaskHandle_t spiTask;
|
||||
|
||||
void spi_enqueuedata(MessageBuffer_t *message);
|
||||
void spi_queuereset();
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of the copyright holder nor the names of the
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
|
||||
The information provided is believed to be accurate and reliable.
|
||||
The copyright holder assumes no responsibility
|
||||
for the consequences of use
|
||||
of such information nor for any infringement of patents or
|
||||
other rights of third parties which may result from its use.
|
||||
No license is granted by implication or otherwise under any patent or
|
||||
patent rights of the copyright holder.
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,133,135,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,133,135,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,166,224,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,166,224,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,23,142,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,23,142,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,52,233,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,7,240,150,61,0,0,0,0,0,0,0,0,28,124,225,61,52,128,215,63,0,0,160,64,0,0,0,0,0,0,0,0,205,204,12,62,103,213,39,62,230,63,76,192,0,0,0,0,0,0,0,0,145,237,60,191,251,58,64,63,177,80,131,64,0,0,0,0,0,0,0,0,93,254,227,62,54,60,133,191,0,0,64,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,52,233,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,59,62,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,59,62,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,24,89,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,48,117,0,0,0,0,24,89,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,169,55,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,168,19,73,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,169,55,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
454,4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,138,80,0,0
|
|
@ -1,5 +0,0 @@
|
||||
#include "bsec_serialized_configurations_iaq.h"
|
||||
|
||||
const uint8_t bsec_config_iaq[454] =
|
||||
{4,7,4,1,61,0,0,0,0,0,0,0,174,1,0,0,48,0,1,0,0,192,168,71,64,49,119,76,0,0,225,68,137,65,0,63,205,204,204,62,0,0,64,63,205,204,204,62,0,0,0,0,216,85,0,100,0,0,0,0,0,0,0,0,28,0,2,0,0,244,1,225,0,25,0,0,128,64,0,0,32,65,144,1,0,0,112,65,0,0,0,63,16,0,3,0,10,215,163,60,10,215,35,59,10,215,35,59,9,0,5,0,0,0,0,0,1,88,0,9,0,229,208,34,62,0,0,0,0,0,0,0,0,218,27,156,62,225,11,67,64,0,0,160,64,0,0,0,0,0,0,0,0,94,75,72,189,93,254,159,64,66,62,160,191,0,0,0,0,0,0,0,0,33,31,180,190,138,176,97,64,65,241,99,190,0,0,0,0,0,0,0,0,167,121,71,61,165,189,41,192,184,30,189,64,12,0,10,0,0,0,0,0,0,0,0,0,229,0,254,0,2,1,5,48,117,100,0,44,1,112,23,151,7,132,3,197,0,92,4,144,1,64,1,64,1,144,1,48,117,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,48,117,48,117,100,0,100,0,100,0,100,0,48,117,48,117,48,117,100,0,100,0,100,0,48,117,48,117,100,0,100,0,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,112,23,255,255,255,255,255,255,255,255,220,5,220,5,220,5,255,255,255,255,255,255,220,5,220,5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,44,1,0,0,0,0,138,80,0,0};
|
||||
|
@ -1,4 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t bsec_config_iaq[454];
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,282 +0,0 @@
|
||||
# BME680 sensor API
|
||||
|
||||
## Introduction
|
||||
|
||||
This package contains the Bosch Sensortec's BME680 gas sensor API
|
||||
|
||||
The sensor driver package includes bme680.h, bme680.c and bme680_defs.h files
|
||||
|
||||
## Version
|
||||
|
||||
File | Version | Date
|
||||
--------------|---------|-------------
|
||||
bme680.c | 3.5.9 | 19 Jun 2018
|
||||
bme680.h | 3.5.9 | 19 Jun 2018
|
||||
bme680_defs.h | 3.5.9 | 19 Jun 2018
|
||||
|
||||
## Integration details
|
||||
|
||||
* Integrate bme680.h, bme680_defs.h and bme680.c file in to your project.
|
||||
* Include the bme680.h file in your code like below.
|
||||
|
||||
``` c
|
||||
#include "bme680.h"
|
||||
```
|
||||
|
||||
## File information
|
||||
|
||||
* bme680_defs.h : This header file has the constants, macros and datatype declarations.
|
||||
* bme680.h : This header file contains the declarations of the sensor driver APIs.
|
||||
* bme680.c : This source file contains the definitions of the sensor driver APIs.
|
||||
|
||||
## Supported sensor interfaces
|
||||
|
||||
* SPI 4-wire
|
||||
* I2C
|
||||
|
||||
## Usage guide
|
||||
|
||||
### Initializing the sensor
|
||||
|
||||
To initialize the sensor, you will first need to create a device structure. You
|
||||
can do this by creating an instance of the structure bme680_dev. Then go on to
|
||||
fill in the various parameters as shown below
|
||||
|
||||
#### Example for SPI 4-Wire
|
||||
|
||||
``` c
|
||||
struct bme680_dev gas_sensor;
|
||||
|
||||
/* You may assign a chip select identifier to be handled later */
|
||||
gas_sensor.dev_id = 0;
|
||||
gas_sensor.intf = BME680_SPI_INTF;
|
||||
gas_sensor.read = user_spi_read;
|
||||
gas_sensor.write = user_spi_write;
|
||||
gas_sensor.delay_ms = user_delay_ms;
|
||||
/* amb_temp can be set to 25 prior to configuring the gas sensor
|
||||
* or by performing a few temperature readings without operating the gas sensor.
|
||||
*/
|
||||
gas_sensor.amb_temp = 25;
|
||||
|
||||
int8_t rslt = BME680_OK;
|
||||
rslt = bme680_init(&gas_sensor);
|
||||
```
|
||||
|
||||
#### Example for I2C
|
||||
|
||||
``` c
|
||||
struct bme680_dev gas_sensor;
|
||||
|
||||
gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY;
|
||||
gas_sensor.intf = BME680_I2C_INTF;
|
||||
gas_sensor.read = i2c_read;
|
||||
gas_sensor.write = i2c_write;
|
||||
gas_sensor.delay_ms = user_delay_ms;
|
||||
/* amb_temp can be set to 25 prior to configuring the gas sensor
|
||||
* or by performing a few temperature readings without operating the gas sensor.
|
||||
*/
|
||||
gas_sensor.amb_temp = 25;
|
||||
|
||||
|
||||
int8_t rslt = BME680_OK;
|
||||
rslt = bme680_init(&gas_sensor);
|
||||
```
|
||||
|
||||
Regarding compensation functions for temperature, pressure, humidity and gas we have two implementations.
|
||||
|
||||
- Integer version
|
||||
- floating point version
|
||||
|
||||
By default, Integer version is used in the API
|
||||
|
||||
If the user needs the floating point version, the user has to un-comment BME680_FLOAT_POINT_COMPENSATION macro
|
||||
in bme680_defs.h file or to add it in the compiler flags.
|
||||
|
||||
### Configuring the sensor
|
||||
|
||||
#### Example for configuring the sensor in forced mode
|
||||
|
||||
``` c
|
||||
uint8_t set_required_settings;
|
||||
|
||||
/* Set the temperature, pressure and humidity settings */
|
||||
gas_sensor.tph_sett.os_hum = BME680_OS_2X;
|
||||
gas_sensor.tph_sett.os_pres = BME680_OS_4X;
|
||||
gas_sensor.tph_sett.os_temp = BME680_OS_8X;
|
||||
gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3;
|
||||
|
||||
/* Set the remaining gas sensor settings and link the heating profile */
|
||||
gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
|
||||
/* Create a ramp heat waveform in 3 steps */
|
||||
gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */
|
||||
gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */
|
||||
|
||||
/* Select the power mode */
|
||||
/* Must be set before writing the sensor configuration */
|
||||
gas_sensor.power_mode = BME680_FORCED_MODE;
|
||||
|
||||
/* Set the required sensor settings needed */
|
||||
set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL
|
||||
| BME680_GAS_SENSOR_SEL;
|
||||
|
||||
/* Set the desired sensor configuration */
|
||||
rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor);
|
||||
|
||||
/* Set the power mode */
|
||||
rslt = bme680_set_sensor_mode(&gas_sensor);
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Reading sensor data
|
||||
|
||||
#### Example for reading all sensor data
|
||||
|
||||
``` c
|
||||
/* Get the total measurement duration so as to sleep or wait till the
|
||||
* measurement is complete */
|
||||
uint16_t meas_period;
|
||||
bme680_get_profile_dur(&meas_period, &gas_sensor);
|
||||
|
||||
struct bme680_field_data data;
|
||||
|
||||
while(1)
|
||||
{
|
||||
user_delay_ms(meas_period); /* Delay till the measurement is ready */
|
||||
|
||||
rslt = bme680_get_sensor_data(&data, &gas_sensor);
|
||||
|
||||
printf("T: %.2f degC, P: %.2f hPa, H %.2f %%rH ", data.temperature / 100.0f,
|
||||
data.pressure / 100.0f, data.humidity / 1000.0f );
|
||||
/* Avoid using measurements from an unstable heating setup */
|
||||
if(data.status & BME680_GASM_VALID_MSK)
|
||||
printf(", G: %d ohms", data.gas_resistance);
|
||||
|
||||
printf("\r\n");
|
||||
|
||||
/* Trigger the next measurement if you would like to read data out continuously */
|
||||
if (gas_sensor.power_mode == BME680_FORCED_MODE) {
|
||||
rslt = bme680_set_sensor_mode(&gas_sensor);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Templates for function pointers
|
||||
|
||||
``` c
|
||||
|
||||
void user_delay_ms(uint32_t period)
|
||||
{
|
||||
/*
|
||||
* Return control or wait,
|
||||
* for a period amount of milliseconds
|
||||
*/
|
||||
}
|
||||
|
||||
int8_t user_spi_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
||||
{
|
||||
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
||||
|
||||
/*
|
||||
* The parameter dev_id can be used as a variable to select which Chip Select pin has
|
||||
* to be set low to activate the relevant device on the SPI bus
|
||||
*/
|
||||
|
||||
/*
|
||||
* Data on the bus should be like
|
||||
* |----------------+---------------------+-------------|
|
||||
* | MOSI | MISO | Chip Select |
|
||||
* |----------------+---------------------|-------------|
|
||||
* | (don't care) | (don't care) | HIGH |
|
||||
* | (reg_addr) | (don't care) | LOW |
|
||||
* | (don't care) | (reg_data[0]) | LOW |
|
||||
* | (....) | (....) | LOW |
|
||||
* | (don't care) | (reg_data[len - 1]) | LOW |
|
||||
* | (don't care) | (don't care) | HIGH |
|
||||
* |----------------+---------------------|-------------|
|
||||
*/
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
int8_t user_spi_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
||||
{
|
||||
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
||||
|
||||
/*
|
||||
* The parameter dev_id can be used as a variable to select which Chip Select pin has
|
||||
* to be set low to activate the relevant device on the SPI bus
|
||||
*/
|
||||
|
||||
/*
|
||||
* Data on the bus should be like
|
||||
* |---------------------+--------------+-------------|
|
||||
* | MOSI | MISO | Chip Select |
|
||||
* |---------------------+--------------|-------------|
|
||||
* | (don't care) | (don't care) | HIGH |
|
||||
* | (reg_addr) | (don't care) | LOW |
|
||||
* | (reg_data[0]) | (don't care) | LOW |
|
||||
* | (....) | (....) | LOW |
|
||||
* | (reg_data[len - 1]) | (don't care) | LOW |
|
||||
* | (don't care) | (don't care) | HIGH |
|
||||
* |---------------------+--------------|-------------|
|
||||
*/
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
||||
{
|
||||
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
||||
|
||||
/*
|
||||
* The parameter dev_id can be used as a variable to store the I2C address of the device
|
||||
*/
|
||||
|
||||
/*
|
||||
* Data on the bus should be like
|
||||
* |------------+---------------------|
|
||||
* | I2C action | Data |
|
||||
* |------------+---------------------|
|
||||
* | Start | - |
|
||||
* | Write | (reg_addr) |
|
||||
* | Stop | - |
|
||||
* | Start | - |
|
||||
* | Read | (reg_data[0]) |
|
||||
* | Read | (....) |
|
||||
* | Read | (reg_data[len - 1]) |
|
||||
* | Stop | - |
|
||||
* |------------+---------------------|
|
||||
*/
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
|
||||
{
|
||||
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
|
||||
|
||||
/*
|
||||
* The parameter dev_id can be used as a variable to store the I2C address of the device
|
||||
*/
|
||||
|
||||
/*
|
||||
* Data on the bus should be like
|
||||
* |------------+---------------------|
|
||||
* | I2C action | Data |
|
||||
* |------------+---------------------|
|
||||
* | Start | - |
|
||||
* | Write | (reg_addr) |
|
||||
* | Write | (reg_data[0]) |
|
||||
* | Write | (....) |
|
||||
* | Write | (reg_data[len - 1]) |
|
||||
* | Stop | - |
|
||||
* |------------+---------------------|
|
||||
*/
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
File diff suppressed because it is too large
Load Diff
@ -1,225 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
*
|
||||
* The information provided is believed to be accurate and reliable.
|
||||
* The copyright holder assumes no responsibility
|
||||
* for the consequences of use
|
||||
* of such information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use.
|
||||
* No license is granted by implication or otherwise under any patent or
|
||||
* patent rights of the copyright holder.
|
||||
*
|
||||
* @file bme680.h
|
||||
* @date 19 Jun 2018
|
||||
* @version 3.5.9
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
/*! @file bme680.h
|
||||
@brief Sensor driver for BME680 sensor */
|
||||
/*!
|
||||
* @defgroup BME680 SENSOR API
|
||||
* @{*/
|
||||
#ifndef BME680_H_
|
||||
#define BME680_H_
|
||||
|
||||
/*! CPP guard */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Header includes */
|
||||
#include "bme680_defs.h"
|
||||
|
||||
/* function prototype declarations */
|
||||
/*!
|
||||
* @brief This API is the entry point.
|
||||
* It reads the chip-id and calibration data from the sensor.
|
||||
*
|
||||
* @param[in,out] dev : Structure instance of bme680_dev
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_init(struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API writes the given data to the register address
|
||||
* of the sensor.
|
||||
*
|
||||
* @param[in] reg_addr : Register address from where the data to be written.
|
||||
* @param[in] reg_data : Pointer to data buffer which is to be written
|
||||
* in the sensor.
|
||||
* @param[in] len : No of bytes of data to write..
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API reads the data from the given register address of the sensor.
|
||||
*
|
||||
* @param[in] reg_addr : Register address from where the data to be read
|
||||
* @param[out] reg_data : Pointer to data buffer to store the read data.
|
||||
* @param[in] len : No of bytes of data to be read.
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API performs the soft reset of the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
|
||||
*/
|
||||
int8_t bme680_soft_reset(struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to set the power mode of the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev
|
||||
* @note : Pass the value to bme680_dev.power_mode structure variable.
|
||||
*
|
||||
* value | mode
|
||||
* -------------|------------------
|
||||
* 0x00 | BME680_SLEEP_MODE
|
||||
* 0x01 | BME680_FORCED_MODE
|
||||
*
|
||||
* * @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_set_sensor_mode(struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to get the power mode of the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev
|
||||
* @note : bme680_dev.power_mode structure variable hold the power mode.
|
||||
*
|
||||
* value | mode
|
||||
* ---------|------------------
|
||||
* 0x00 | BME680_SLEEP_MODE
|
||||
* 0x01 | BME680_FORCED_MODE
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_get_sensor_mode(struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to set the profile duration of the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
* @param[in] duration : Duration of the measurement in ms.
|
||||
*
|
||||
* @return Nothing
|
||||
*/
|
||||
void bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to get the profile duration of the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
* @param[in] duration : Duration of the measurement in ms.
|
||||
*
|
||||
* @return Nothing
|
||||
*/
|
||||
void bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API reads the pressure, temperature and humidity and gas data
|
||||
* from the sensor, compensates the data and store it in the bme680_data
|
||||
* structure instance passed by the user.
|
||||
*
|
||||
* @param[out] data: Structure instance to hold the data.
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error
|
||||
*/
|
||||
int8_t bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to set the oversampling, filter and T,P,H, gas selection
|
||||
* settings in the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
* @param[in] desired_settings : Variable used to select the settings which
|
||||
* are to be set in the sensor.
|
||||
*
|
||||
* Macros | Functionality
|
||||
*---------------------------------|----------------------------------------------
|
||||
* BME680_OST_SEL | To set temperature oversampling.
|
||||
* BME680_OSP_SEL | To set pressure oversampling.
|
||||
* BME680_OSH_SEL | To set humidity oversampling.
|
||||
* BME680_GAS_MEAS_SEL | To set gas measurement setting.
|
||||
* BME680_FILTER_SEL | To set filter setting.
|
||||
* BME680_HCNTRL_SEL | To set humidity control setting.
|
||||
* BME680_RUN_GAS_SEL | To set run gas setting.
|
||||
* BME680_NBCONV_SEL | To set NB conversion setting.
|
||||
* BME680_GAS_SENSOR_SEL | To set all gas sensor related settings
|
||||
*
|
||||
* @note : Below are the macros to be used by the user for selecting the
|
||||
* desired settings. User can do OR operation of these macros for configuring
|
||||
* multiple settings.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
|
||||
*/
|
||||
int8_t bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev);
|
||||
|
||||
/*!
|
||||
* @brief This API is used to get the oversampling, filter and T,P,H, gas selection
|
||||
* settings in the sensor.
|
||||
*
|
||||
* @param[in] dev : Structure instance of bme680_dev.
|
||||
* @param[in] desired_settings : Variable used to select the settings which
|
||||
* are to be get from the sensor.
|
||||
*
|
||||
* @return Result of API execution status
|
||||
* @retval zero -> Success / +ve value -> Warning / -ve value -> Error.
|
||||
*/
|
||||
int8_t bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* End of CPP guard */
|
||||
#endif /* BME680_H_ */
|
||||
/** @}*/
|
@ -1,545 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
*
|
||||
* The information provided is believed to be accurate and reliable.
|
||||
* The copyright holder assumes no responsibility
|
||||
* for the consequences of use
|
||||
* of such information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use.
|
||||
* No license is granted by implication or otherwise under any patent or
|
||||
* patent rights of the copyright holder.
|
||||
*
|
||||
* @file bme680_defs.h
|
||||
* @date 19 Jun 2018
|
||||
* @version 3.5.9
|
||||
* @brief
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file bme680_defs.h
|
||||
@brief Sensor driver for BME680 sensor */
|
||||
/*!
|
||||
* @defgroup BME680 SENSOR API
|
||||
* @brief
|
||||
* @{*/
|
||||
#ifndef BME680_DEFS_H_
|
||||
#define BME680_DEFS_H_
|
||||
|
||||
/********************************************************/
|
||||
/* header includes */
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
/*! @name Common macros */
|
||||
/******************************************************************************/
|
||||
|
||||
#if !defined(UINT8_C) && !defined(INT8_C)
|
||||
#define INT8_C(x) S8_C(x)
|
||||
#define UINT8_C(x) U8_C(x)
|
||||
#endif
|
||||
|
||||
#if !defined(UINT16_C) && !defined(INT16_C)
|
||||
#define INT16_C(x) S16_C(x)
|
||||
#define UINT16_C(x) U16_C(x)
|
||||
#endif
|
||||
|
||||
#if !defined(INT32_C) && !defined(UINT32_C)
|
||||
#define INT32_C(x) S32_C(x)
|
||||
#define UINT32_C(x) U32_C(x)
|
||||
#endif
|
||||
|
||||
#if !defined(INT64_C) && !defined(UINT64_C)
|
||||
#define INT64_C(x) S64_C(x)
|
||||
#define UINT64_C(x) U64_C(x)
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**\name C standard macros */
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** BME680 configuration macros */
|
||||
/** Enable or un-comment the macro to provide floating point data output */
|
||||
#ifndef BME680_FLOAT_POINT_COMPENSATION
|
||||
//#define BME680_FLOAT_POINT_COMPENSATION
|
||||
#endif
|
||||
|
||||
/** BME680 General config */
|
||||
#define BME680_POLL_PERIOD_MS UINT8_C(10)
|
||||
|
||||
/** BME680 I2C addresses */
|
||||
#define BME680_I2C_ADDR_PRIMARY UINT8_C(0x76)
|
||||
#define BME680_I2C_ADDR_SECONDARY UINT8_C(0x77)
|
||||
|
||||
/** BME680 unique chip identifier */
|
||||
#define BME680_CHIP_ID UINT8_C(0x61)
|
||||
|
||||
/** BME680 coefficients related defines */
|
||||
#define BME680_COEFF_SIZE UINT8_C(41)
|
||||
#define BME680_COEFF_ADDR1_LEN UINT8_C(25)
|
||||
#define BME680_COEFF_ADDR2_LEN UINT8_C(16)
|
||||
|
||||
/** BME680 field_x related defines */
|
||||
#define BME680_FIELD_LENGTH UINT8_C(15)
|
||||
#define BME680_FIELD_ADDR_OFFSET UINT8_C(17)
|
||||
|
||||
/** Soft reset command */
|
||||
#define BME680_SOFT_RESET_CMD UINT8_C(0xb6)
|
||||
|
||||
/** Error code definitions */
|
||||
#define BME680_OK INT8_C(0)
|
||||
/* Errors */
|
||||
#define BME680_E_NULL_PTR INT8_C(-1)
|
||||
#define BME680_E_COM_FAIL INT8_C(-2)
|
||||
#define BME680_E_DEV_NOT_FOUND INT8_C(-3)
|
||||
#define BME680_E_INVALID_LENGTH INT8_C(-4)
|
||||
|
||||
/* Warnings */
|
||||
#define BME680_W_DEFINE_PWR_MODE INT8_C(1)
|
||||
#define BME680_W_NO_NEW_DATA INT8_C(2)
|
||||
|
||||
/* Info's */
|
||||
#define BME680_I_MIN_CORRECTION UINT8_C(1)
|
||||
#define BME680_I_MAX_CORRECTION UINT8_C(2)
|
||||
|
||||
/** Register map */
|
||||
/** Other coefficient's address */
|
||||
#define BME680_ADDR_RES_HEAT_VAL_ADDR UINT8_C(0x00)
|
||||
#define BME680_ADDR_RES_HEAT_RANGE_ADDR UINT8_C(0x02)
|
||||
#define BME680_ADDR_RANGE_SW_ERR_ADDR UINT8_C(0x04)
|
||||
#define BME680_ADDR_SENS_CONF_START UINT8_C(0x5A)
|
||||
#define BME680_ADDR_GAS_CONF_START UINT8_C(0x64)
|
||||
|
||||
/** Field settings */
|
||||
#define BME680_FIELD0_ADDR UINT8_C(0x1d)
|
||||
|
||||
/** Heater settings */
|
||||
#define BME680_RES_HEAT0_ADDR UINT8_C(0x5a)
|
||||
#define BME680_GAS_WAIT0_ADDR UINT8_C(0x64)
|
||||
|
||||
/** Sensor configuration registers */
|
||||
#define BME680_CONF_HEAT_CTRL_ADDR UINT8_C(0x70)
|
||||
#define BME680_CONF_ODR_RUN_GAS_NBC_ADDR UINT8_C(0x71)
|
||||
#define BME680_CONF_OS_H_ADDR UINT8_C(0x72)
|
||||
#define BME680_MEM_PAGE_ADDR UINT8_C(0xf3)
|
||||
#define BME680_CONF_T_P_MODE_ADDR UINT8_C(0x74)
|
||||
#define BME680_CONF_ODR_FILT_ADDR UINT8_C(0x75)
|
||||
|
||||
/** Coefficient's address */
|
||||
#define BME680_COEFF_ADDR1 UINT8_C(0x89)
|
||||
#define BME680_COEFF_ADDR2 UINT8_C(0xe1)
|
||||
|
||||
/** Chip identifier */
|
||||
#define BME680_CHIP_ID_ADDR UINT8_C(0xd0)
|
||||
|
||||
/** Soft reset register */
|
||||
#define BME680_SOFT_RESET_ADDR UINT8_C(0xe0)
|
||||
|
||||
/** Heater control settings */
|
||||
#define BME680_ENABLE_HEATER UINT8_C(0x00)
|
||||
#define BME680_DISABLE_HEATER UINT8_C(0x08)
|
||||
|
||||
/** Gas measurement settings */
|
||||
#define BME680_DISABLE_GAS_MEAS UINT8_C(0x00)
|
||||
#define BME680_ENABLE_GAS_MEAS UINT8_C(0x01)
|
||||
|
||||
/** Over-sampling settings */
|
||||
#define BME680_OS_NONE UINT8_C(0)
|
||||
#define BME680_OS_1X UINT8_C(1)
|
||||
#define BME680_OS_2X UINT8_C(2)
|
||||
#define BME680_OS_4X UINT8_C(3)
|
||||
#define BME680_OS_8X UINT8_C(4)
|
||||
#define BME680_OS_16X UINT8_C(5)
|
||||
|
||||
/** IIR filter settings */
|
||||
#define BME680_FILTER_SIZE_0 UINT8_C(0)
|
||||
#define BME680_FILTER_SIZE_1 UINT8_C(1)
|
||||
#define BME680_FILTER_SIZE_3 UINT8_C(2)
|
||||
#define BME680_FILTER_SIZE_7 UINT8_C(3)
|
||||
#define BME680_FILTER_SIZE_15 UINT8_C(4)
|
||||
#define BME680_FILTER_SIZE_31 UINT8_C(5)
|
||||
#define BME680_FILTER_SIZE_63 UINT8_C(6)
|
||||
#define BME680_FILTER_SIZE_127 UINT8_C(7)
|
||||
|
||||
/** Power mode settings */
|
||||
#define BME680_SLEEP_MODE UINT8_C(0)
|
||||
#define BME680_FORCED_MODE UINT8_C(1)
|
||||
|
||||
/** Delay related macro declaration */
|
||||
#define BME680_RESET_PERIOD UINT32_C(10)
|
||||
|
||||
/** SPI memory page settings */
|
||||
#define BME680_MEM_PAGE0 UINT8_C(0x10)
|
||||
#define BME680_MEM_PAGE1 UINT8_C(0x00)
|
||||
|
||||
/** Ambient humidity shift value for compensation */
|
||||
#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4)
|
||||
|
||||
/** Run gas enable and disable settings */
|
||||
#define BME680_RUN_GAS_DISABLE UINT8_C(0)
|
||||
#define BME680_RUN_GAS_ENABLE UINT8_C(1)
|
||||
|
||||
/** Buffer length macro declaration */
|
||||
#define BME680_TMP_BUFFER_LENGTH UINT8_C(40)
|
||||
#define BME680_REG_BUFFER_LENGTH UINT8_C(6)
|
||||
#define BME680_FIELD_DATA_LENGTH UINT8_C(3)
|
||||
#define BME680_GAS_REG_BUF_LENGTH UINT8_C(20)
|
||||
|
||||
/** Settings selector */
|
||||
#define BME680_OST_SEL UINT16_C(1)
|
||||
#define BME680_OSP_SEL UINT16_C(2)
|
||||
#define BME680_OSH_SEL UINT16_C(4)
|
||||
#define BME680_GAS_MEAS_SEL UINT16_C(8)
|
||||
#define BME680_FILTER_SEL UINT16_C(16)
|
||||
#define BME680_HCNTRL_SEL UINT16_C(32)
|
||||
#define BME680_RUN_GAS_SEL UINT16_C(64)
|
||||
#define BME680_NBCONV_SEL UINT16_C(128)
|
||||
#define BME680_GAS_SENSOR_SEL (BME680_GAS_MEAS_SEL | BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)
|
||||
|
||||
/** Number of conversion settings*/
|
||||
#define BME680_NBCONV_MIN UINT8_C(0)
|
||||
#define BME680_NBCONV_MAX UINT8_C(10)
|
||||
|
||||
/** Mask definitions */
|
||||
#define BME680_GAS_MEAS_MSK UINT8_C(0x30)
|
||||
#define BME680_NBCONV_MSK UINT8_C(0X0F)
|
||||
#define BME680_FILTER_MSK UINT8_C(0X1C)
|
||||
#define BME680_OST_MSK UINT8_C(0XE0)
|
||||
#define BME680_OSP_MSK UINT8_C(0X1C)
|
||||
#define BME680_OSH_MSK UINT8_C(0X07)
|
||||
#define BME680_HCTRL_MSK UINT8_C(0x08)
|
||||
#define BME680_RUN_GAS_MSK UINT8_C(0x10)
|
||||
#define BME680_MODE_MSK UINT8_C(0x03)
|
||||
#define BME680_RHRANGE_MSK UINT8_C(0x30)
|
||||
#define BME680_RSERROR_MSK UINT8_C(0xf0)
|
||||
#define BME680_NEW_DATA_MSK UINT8_C(0x80)
|
||||
#define BME680_GAS_INDEX_MSK UINT8_C(0x0f)
|
||||
#define BME680_GAS_RANGE_MSK UINT8_C(0x0f)
|
||||
#define BME680_GASM_VALID_MSK UINT8_C(0x20)
|
||||
#define BME680_HEAT_STAB_MSK UINT8_C(0x10)
|
||||
#define BME680_MEM_PAGE_MSK UINT8_C(0x10)
|
||||
#define BME680_SPI_RD_MSK UINT8_C(0x80)
|
||||
#define BME680_SPI_WR_MSK UINT8_C(0x7f)
|
||||
#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F)
|
||||
|
||||
/** Bit position definitions for sensor settings */
|
||||
#define BME680_GAS_MEAS_POS UINT8_C(4)
|
||||
#define BME680_FILTER_POS UINT8_C(2)
|
||||
#define BME680_OST_POS UINT8_C(5)
|
||||
#define BME680_OSP_POS UINT8_C(2)
|
||||
#define BME680_RUN_GAS_POS UINT8_C(4)
|
||||
|
||||
/** Array Index to Field data mapping for Calibration Data*/
|
||||
#define BME680_T2_LSB_REG (1)
|
||||
#define BME680_T2_MSB_REG (2)
|
||||
#define BME680_T3_REG (3)
|
||||
#define BME680_P1_LSB_REG (5)
|
||||
#define BME680_P1_MSB_REG (6)
|
||||
#define BME680_P2_LSB_REG (7)
|
||||
#define BME680_P2_MSB_REG (8)
|
||||
#define BME680_P3_REG (9)
|
||||
#define BME680_P4_LSB_REG (11)
|
||||
#define BME680_P4_MSB_REG (12)
|
||||
#define BME680_P5_LSB_REG (13)
|
||||
#define BME680_P5_MSB_REG (14)
|
||||
#define BME680_P7_REG (15)
|
||||
#define BME680_P6_REG (16)
|
||||
#define BME680_P8_LSB_REG (19)
|
||||
#define BME680_P8_MSB_REG (20)
|
||||
#define BME680_P9_LSB_REG (21)
|
||||
#define BME680_P9_MSB_REG (22)
|
||||
#define BME680_P10_REG (23)
|
||||
#define BME680_H2_MSB_REG (25)
|
||||
#define BME680_H2_LSB_REG (26)
|
||||
#define BME680_H1_LSB_REG (26)
|
||||
#define BME680_H1_MSB_REG (27)
|
||||
#define BME680_H3_REG (28)
|
||||
#define BME680_H4_REG (29)
|
||||
#define BME680_H5_REG (30)
|
||||
#define BME680_H6_REG (31)
|
||||
#define BME680_H7_REG (32)
|
||||
#define BME680_T1_LSB_REG (33)
|
||||
#define BME680_T1_MSB_REG (34)
|
||||
#define BME680_GH2_LSB_REG (35)
|
||||
#define BME680_GH2_MSB_REG (36)
|
||||
#define BME680_GH1_REG (37)
|
||||
#define BME680_GH3_REG (38)
|
||||
|
||||
/** BME680 register buffer index settings*/
|
||||
#define BME680_REG_FILTER_INDEX UINT8_C(5)
|
||||
#define BME680_REG_TEMP_INDEX UINT8_C(4)
|
||||
#define BME680_REG_PRES_INDEX UINT8_C(4)
|
||||
#define BME680_REG_HUM_INDEX UINT8_C(2)
|
||||
#define BME680_REG_NBCONV_INDEX UINT8_C(1)
|
||||
#define BME680_REG_RUN_GAS_INDEX UINT8_C(1)
|
||||
#define BME680_REG_HCTRL_INDEX UINT8_C(0)
|
||||
|
||||
/** BME680 pressure calculation macros */
|
||||
/*! This max value is used to provide precedence to multiplication or division
|
||||
* in pressure compensation equation to achieve least loss of precision and
|
||||
* avoiding overflows.
|
||||
* i.e Comparing value, BME680_MAX_OVERFLOW_VAL = INT32_C(1 << 30)
|
||||
*/
|
||||
#define BME680_MAX_OVERFLOW_VAL INT32_C(0x40000000)
|
||||
|
||||
/** Macro to combine two 8 bit data's to form a 16 bit data */
|
||||
#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb)
|
||||
|
||||
/** Macro to SET and GET BITS of a register */
|
||||
#define BME680_SET_BITS(reg_data, bitname, data) \
|
||||
((reg_data & ~(bitname##_MSK)) | \
|
||||
((data << bitname##_POS) & bitname##_MSK))
|
||||
#define BME680_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \
|
||||
(bitname##_POS))
|
||||
|
||||
/** Macro variant to handle the bitname position if it is zero */
|
||||
#define BME680_SET_BITS_POS_0(reg_data, bitname, data) \
|
||||
((reg_data & ~(bitname##_MSK)) | \
|
||||
(data & bitname##_MSK))
|
||||
#define BME680_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK))
|
||||
|
||||
/** Type definitions */
|
||||
/*!
|
||||
* Generic communication function pointer
|
||||
* @param[in] dev_id: Place holder to store the id of the device structure
|
||||
* Can be used to store the index of the Chip select or
|
||||
* I2C address of the device.
|
||||
* @param[in] reg_addr: Used to select the register the where data needs to
|
||||
* be read from or written to.
|
||||
* @param[in/out] reg_data: Data array to read/write
|
||||
* @param[in] len: Length of the data array
|
||||
*/
|
||||
typedef int8_t (*bme680_com_fptr_t)(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len);
|
||||
|
||||
/*!
|
||||
* Delay function pointer
|
||||
* @param[in] period: Time period in milliseconds
|
||||
*/
|
||||
typedef void (*bme680_delay_fptr_t)(uint32_t period);
|
||||
|
||||
/*!
|
||||
* @brief Interface selection Enumerations
|
||||
*/
|
||||
enum bme680_intf {
|
||||
/*! SPI interface */
|
||||
BME680_SPI_INTF,
|
||||
/*! I2C interface */
|
||||
BME680_I2C_INTF
|
||||
};
|
||||
|
||||
/* structure definitions */
|
||||
/*!
|
||||
* @brief Sensor field data structure
|
||||
*/
|
||||
struct bme680_field_data {
|
||||
/*! Contains new_data, gasm_valid & heat_stab */
|
||||
uint8_t status;
|
||||
/*! The index of the heater profile used */
|
||||
uint8_t gas_index;
|
||||
/*! Measurement index to track order */
|
||||
uint8_t meas_index;
|
||||
|
||||
#ifndef BME680_FLOAT_POINT_COMPENSATION
|
||||
/*! Temperature in degree celsius x100 */
|
||||
int16_t temperature;
|
||||
/*! Pressure in Pascal */
|
||||
uint32_t pressure;
|
||||
/*! Humidity in % relative humidity x1000 */
|
||||
uint32_t humidity;
|
||||
/*! Gas resistance in Ohms */
|
||||
uint32_t gas_resistance;
|
||||
#else
|
||||
/*! Temperature in degree celsius */
|
||||
float temperature;
|
||||
/*! Pressure in Pascal */
|
||||
float pressure;
|
||||
/*! Humidity in % relative humidity x1000 */
|
||||
float humidity;
|
||||
/*! Gas resistance in Ohms */
|
||||
float gas_resistance;
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Structure to hold the Calibration data
|
||||
*/
|
||||
struct bme680_calib_data {
|
||||
/*! Variable to store calibrated humidity data */
|
||||
uint16_t par_h1;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
uint16_t par_h2;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
int8_t par_h3;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
int8_t par_h4;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
int8_t par_h5;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
uint8_t par_h6;
|
||||
/*! Variable to store calibrated humidity data */
|
||||
int8_t par_h7;
|
||||
/*! Variable to store calibrated gas data */
|
||||
int8_t par_gh1;
|
||||
/*! Variable to store calibrated gas data */
|
||||
int16_t par_gh2;
|
||||
/*! Variable to store calibrated gas data */
|
||||
int8_t par_gh3;
|
||||
/*! Variable to store calibrated temperature data */
|
||||
uint16_t par_t1;
|
||||
/*! Variable to store calibrated temperature data */
|
||||
int16_t par_t2;
|
||||
/*! Variable to store calibrated temperature data */
|
||||
int8_t par_t3;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
uint16_t par_p1;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int16_t par_p2;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int8_t par_p3;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int16_t par_p4;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int16_t par_p5;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int8_t par_p6;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int8_t par_p7;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int16_t par_p8;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
int16_t par_p9;
|
||||
/*! Variable to store calibrated pressure data */
|
||||
uint8_t par_p10;
|
||||
|
||||
#ifndef BME680_FLOAT_POINT_COMPENSATION
|
||||
/*! Variable to store t_fine size */
|
||||
int32_t t_fine;
|
||||
#else
|
||||
/*! Variable to store t_fine size */
|
||||
float t_fine;
|
||||
#endif
|
||||
/*! Variable to store heater resistance range */
|
||||
uint8_t res_heat_range;
|
||||
/*! Variable to store heater resistance value */
|
||||
int8_t res_heat_val;
|
||||
/*! Variable to store error range */
|
||||
int8_t range_sw_err;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief BME680 sensor settings structure which comprises of ODR,
|
||||
* over-sampling and filter settings.
|
||||
*/
|
||||
struct bme680_tph_sett {
|
||||
/*! Humidity oversampling */
|
||||
uint8_t os_hum;
|
||||
/*! Temperature oversampling */
|
||||
uint8_t os_temp;
|
||||
/*! Pressure oversampling */
|
||||
uint8_t os_pres;
|
||||
/*! Filter coefficient */
|
||||
uint8_t filter;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief BME680 gas sensor which comprises of gas settings
|
||||
* and status parameters
|
||||
*/
|
||||
struct bme680_gas_sett {
|
||||
/*! Variable to store nb conversion */
|
||||
uint8_t nb_conv;
|
||||
/*! Variable to store heater control */
|
||||
uint8_t heatr_ctrl;
|
||||
/*! Run gas enable value */
|
||||
uint8_t run_gas;
|
||||
/*! Heater temperature value */
|
||||
uint16_t heatr_temp;
|
||||
/*! Duration profile value */
|
||||
uint16_t heatr_dur;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief BME680 device structure
|
||||
*/
|
||||
struct bme680_dev {
|
||||
/*! Chip Id */
|
||||
uint8_t chip_id;
|
||||
/*! Device Id */
|
||||
uint8_t dev_id;
|
||||
/*! SPI/I2C interface */
|
||||
enum bme680_intf intf;
|
||||
/*! Memory page used */
|
||||
uint8_t mem_page;
|
||||
/*! Ambient temperature in Degree C */
|
||||
int8_t amb_temp;
|
||||
/*! Sensor calibration data */
|
||||
struct bme680_calib_data calib;
|
||||
/*! Sensor settings */
|
||||
struct bme680_tph_sett tph_sett;
|
||||
/*! Gas Sensor settings */
|
||||
struct bme680_gas_sett gas_sett;
|
||||
/*! Sensor power modes */
|
||||
uint8_t power_mode;
|
||||
/*! New sensor fields */
|
||||
uint8_t new_fields;
|
||||
/*! Store the info messages */
|
||||
uint8_t info_msg;
|
||||
/*! Bus read function pointer */
|
||||
bme680_com_fptr_t read;
|
||||
/*! Bus write function pointer */
|
||||
bme680_com_fptr_t write;
|
||||
/*! delay function pointer */
|
||||
bme680_delay_fptr_t delay_ms;
|
||||
/*! Communication function result */
|
||||
int8_t com_rslt;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* BME680_DEFS_H_ */
|
||||
/** @}*/
|
||||
/** @}*/
|
@ -1,498 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
*
|
||||
* The information provided is believed to be accurate and reliable.
|
||||
* The copyright holder assumes no responsibility
|
||||
* for the consequences of use
|
||||
* of such information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use.
|
||||
* No license is granted by implication or otherwise under any patent or
|
||||
* patent rights of the copyright holder.
|
||||
*
|
||||
* @file bsec.cpp
|
||||
* @date 31 Jan 2018
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bsec.h"
|
||||
|
||||
TwoWire *Bsec::wireObj = NULL;
|
||||
SPIClass *Bsec::spiObj = NULL;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
Bsec::Bsec() {
|
||||
nextCall = 0;
|
||||
version.major = 0;
|
||||
version.minor = 0;
|
||||
version.major_bugfix = 0;
|
||||
version.minor_bugfix = 0;
|
||||
millisOverflowCounter = 0;
|
||||
lastTime = 0;
|
||||
bme680Status = BME680_OK;
|
||||
outputTimestamp = 0;
|
||||
_tempOffset = 0.0f;
|
||||
status = BSEC_OK;
|
||||
zeroOutputs();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
*/
|
||||
void Bsec::begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read,
|
||||
bme680_com_fptr_t write, bme680_delay_fptr_t idleTask) {
|
||||
_bme680.dev_id = devId;
|
||||
_bme680.intf = intf;
|
||||
_bme680.read = read;
|
||||
_bme680.write = write;
|
||||
_bme680.delay_ms = idleTask;
|
||||
_bme680.amb_temp = 25;
|
||||
_bme680.power_mode = BME680_FORCED_MODE;
|
||||
|
||||
beginCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
*/
|
||||
void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c) {
|
||||
_bme680.dev_id = i2cAddr;
|
||||
_bme680.intf = BME680_I2C_INTF;
|
||||
_bme680.read = Bsec::i2cRead;
|
||||
_bme680.write = Bsec::i2cWrite;
|
||||
_bme680.delay_ms = Bsec::delay_ms;
|
||||
_bme680.amb_temp = 25;
|
||||
_bme680.power_mode = BME680_FORCED_MODE;
|
||||
|
||||
Bsec::wireObj = &i2c;
|
||||
Bsec::wireObj->begin();
|
||||
|
||||
beginCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
*/
|
||||
void Bsec::begin(uint8_t chipSelect, SPIClass &spi) {
|
||||
_bme680.dev_id = chipSelect;
|
||||
_bme680.intf = BME680_SPI_INTF;
|
||||
_bme680.read = Bsec::spiTransfer;
|
||||
_bme680.write = Bsec::spiTransfer;
|
||||
_bme680.delay_ms = Bsec::delay_ms;
|
||||
_bme680.amb_temp = 25;
|
||||
_bme680.power_mode = BME680_FORCED_MODE;
|
||||
|
||||
pinMode(chipSelect, OUTPUT);
|
||||
digitalWrite(chipSelect, HIGH);
|
||||
Bsec::spiObj = &spi;
|
||||
Bsec::spiObj->begin();
|
||||
|
||||
beginCommon();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common code for the begin function
|
||||
*/
|
||||
void Bsec::beginCommon(void) {
|
||||
status = bsec_init();
|
||||
|
||||
getVersion();
|
||||
|
||||
bme680Status = bme680_init(&_bme680);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function that sets the desired sensors and the sample rates
|
||||
*/
|
||||
void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[],
|
||||
uint8_t nSensors, float sampleRate) {
|
||||
bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS],
|
||||
sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
|
||||
uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
|
||||
|
||||
for (uint8_t i = 0; i < nSensors; i++) {
|
||||
virtualSensors[nVirtualSensors].sensor_id = sensorList[i];
|
||||
virtualSensors[nVirtualSensors].sample_rate = sampleRate;
|
||||
nVirtualSensors++;
|
||||
}
|
||||
|
||||
status = bsec_update_subscription(virtualSensors, nVirtualSensors,
|
||||
sensorSettings, &nSensorSettings);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback from the user to trigger reading of data from the BME680,
|
||||
* process and store outputs
|
||||
*/
|
||||
bool Bsec::run(void) {
|
||||
bool newData = false;
|
||||
/* Check if the time has arrived to call do_steps() */
|
||||
int64_t callTimeMs = getTimeMs();
|
||||
|
||||
if (callTimeMs >= nextCall) {
|
||||
|
||||
bsec_bme_settings_t bme680Settings;
|
||||
|
||||
int64_t callTimeNs = callTimeMs * INT64_C(1000000);
|
||||
|
||||
status = bsec_sensor_control(callTimeNs, &bme680Settings);
|
||||
if (status < BSEC_OK)
|
||||
return false;
|
||||
|
||||
nextCall =
|
||||
bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms
|
||||
|
||||
bme680Status = setBme680Config(bme680Settings);
|
||||
if (bme680Status != BME680_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bme680Status = bme680_set_sensor_mode(&_bme680);
|
||||
if (bme680Status != BME680_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Wait for measurement to complete */
|
||||
uint16_t meas_dur = 0;
|
||||
|
||||
bme680_get_profile_dur(&meas_dur, &_bme680);
|
||||
delay_ms(meas_dur);
|
||||
|
||||
newData = readProcessData(callTimeNs, bme680Settings);
|
||||
}
|
||||
|
||||
return newData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to get the state of the algorithm to save to non-volatile
|
||||
* memory
|
||||
*/
|
||||
void Bsec::getState(uint8_t *state) {
|
||||
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
|
||||
status = bsec_get_state(0, state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer,
|
||||
BSEC_MAX_STATE_BLOB_SIZE, &n_serialized_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to set the state of the algorithm from non-volatile memory
|
||||
*/
|
||||
void Bsec::setState(uint8_t *state) {
|
||||
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
|
||||
status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, workBuffer,
|
||||
BSEC_MAX_STATE_BLOB_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to set the configuration of the algorithm from memory
|
||||
*/
|
||||
void Bsec::setConfig(const uint8_t *state) {
|
||||
uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
|
||||
status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE,
|
||||
workBuffer, sizeof(workBuffer));
|
||||
}
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/**
|
||||
* @brief Get the version of the BSEC library
|
||||
*/
|
||||
void Bsec::getVersion(void) { bsec_get_version(&version); }
|
||||
|
||||
/**
|
||||
* @brief Read data from the BME680 and process it
|
||||
*/
|
||||
bool Bsec::readProcessData(int64_t currTimeNs,
|
||||
bsec_bme_settings_t bme680Settings) {
|
||||
bme680Status = bme680_get_sensor_data(&_data, &_bme680);
|
||||
if (bme680Status != BME680_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bsec_input_t inputs[BSEC_MAX_PHYSICAL_SENSOR]; // Temp, Pres, Hum & Gas
|
||||
uint8_t nInputs = 0, nOutputs = 0;
|
||||
|
||||
if (_data.status & BME680_NEW_DATA_MSK) {
|
||||
if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) {
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
|
||||
#ifdef BME680_FLOAT_POINT_COMPENSATION
|
||||
inputs[nInputs].signal = _data.temperature;
|
||||
#else
|
||||
inputs[nInputs].signal = _data.temperature / 100.0f;
|
||||
#endif
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
/* Temperature offset from the real temperature due to external heat
|
||||
* sources */
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
|
||||
inputs[nInputs].signal = _tempOffset;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) {
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
|
||||
#ifdef BME680_FLOAT_POINT_COMPENSATION
|
||||
inputs[nInputs].signal = _data.humidity;
|
||||
#else
|
||||
inputs[nInputs].signal = _data.humidity / 1000.0f;
|
||||
#endif
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE) {
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE;
|
||||
inputs[nInputs].signal = _data.pressure;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
if (bme680Settings.process_data & BSEC_PROCESS_GAS) {
|
||||
inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR;
|
||||
inputs[nInputs].signal = _data.gas_resistance;
|
||||
inputs[nInputs].time_stamp = currTimeNs;
|
||||
nInputs++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nInputs > 0) {
|
||||
nOutputs = BSEC_NUMBER_OUTPUTS;
|
||||
bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS];
|
||||
|
||||
status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs);
|
||||
if (status != BSEC_OK)
|
||||
return false;
|
||||
|
||||
zeroOutputs();
|
||||
|
||||
if (nOutputs > 0) {
|
||||
outputTimestamp =
|
||||
_outputs[0].time_stamp / 1000000; // Convert from ns to ms
|
||||
|
||||
for (uint8_t i = 0; i < nOutputs; i++) {
|
||||
switch (_outputs[i].sensor_id) {
|
||||
case BSEC_OUTPUT_IAQ:
|
||||
iaqEstimate = _outputs[i].signal;
|
||||
iaqAccuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
case BSEC_OUTPUT_STATIC_IAQ:
|
||||
staticIaq = _outputs[i].signal;
|
||||
staticIaqAccuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
case BSEC_OUTPUT_CO2_EQUIVALENT:
|
||||
co2Equivalent = _outputs[i].signal;
|
||||
co2Accuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
|
||||
breathVocEquivalent = _outputs[i].signal;
|
||||
breathVocAccuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_TEMPERATURE:
|
||||
rawTemperature = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_PRESSURE:
|
||||
pressure = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_HUMIDITY:
|
||||
rawHumidity = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_RAW_GAS:
|
||||
gasResistance = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_STABILIZATION_STATUS:
|
||||
stabStatus = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_RUN_IN_STATUS:
|
||||
runInStatus = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
|
||||
temperature = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
|
||||
humidity = _outputs[i].signal;
|
||||
break;
|
||||
case BSEC_OUTPUT_COMPENSATED_GAS:
|
||||
compGasValue = _outputs[i].signal;
|
||||
compGasAccuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
case BSEC_OUTPUT_GAS_PERCENTAGE:
|
||||
gasPercentage = _outputs[i].signal;
|
||||
gasPercentageAcccuracy = _outputs[i].accuracy;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BME680 sensor's configuration
|
||||
*/
|
||||
int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) {
|
||||
_bme680.gas_sett.run_gas = bme680Settings.run_gas;
|
||||
_bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling;
|
||||
_bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling;
|
||||
_bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling;
|
||||
_bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature;
|
||||
_bme680.gas_sett.heatr_dur = bme680Settings.heating_duration;
|
||||
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL |
|
||||
BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
|
||||
return bme680_set_sensor_settings(desired_settings, &_bme680);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to zero the outputs
|
||||
*/
|
||||
void Bsec::zeroOutputs(void) {
|
||||
temperature = 0.0f;
|
||||
pressure = 0.0f;
|
||||
humidity = 0.0f;
|
||||
gasResistance = 0.0f;
|
||||
rawTemperature = 0.0f;
|
||||
rawHumidity = 0.0f;
|
||||
stabStatus = 0.0f;
|
||||
runInStatus = 0.0f;
|
||||
iaqEstimate = 0.0f;
|
||||
iaqAccuracy = 0;
|
||||
staticIaq = 0.0f;
|
||||
staticIaqAccuracy = 0;
|
||||
co2Equivalent = 0.0f;
|
||||
co2Accuracy = 0;
|
||||
breathVocEquivalent = 0.0f;
|
||||
breathVocAccuracy = 0;
|
||||
compGasValue = 0.0f;
|
||||
compGasAccuracy = 0;
|
||||
gasPercentage = 0.0f;
|
||||
gasPercentageAcccuracy = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||
*/
|
||||
int64_t Bsec::getTimeMs(void) {
|
||||
int64_t timeMs = millis();
|
||||
|
||||
if (lastTime > timeMs) { // An overflow occured
|
||||
lastTime = timeMs;
|
||||
millisOverflowCounter++;
|
||||
}
|
||||
|
||||
return timeMs + (millisOverflowCounter * 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Task that delays for a ms period of time
|
||||
*/
|
||||
void Bsec::delay_ms(uint32_t period) {
|
||||
// Wait for a period amount of ms
|
||||
// The system may simply idle, sleep or even perform background tasks
|
||||
delay(period);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Callback function for reading registers over I2C
|
||||
*/
|
||||
int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData,
|
||||
uint16_t length) {
|
||||
uint16_t i;
|
||||
int8_t rslt = 0;
|
||||
if (Bsec::wireObj) {
|
||||
Bsec::wireObj->beginTransmission(devId);
|
||||
Bsec::wireObj->write(regAddr);
|
||||
rslt = Bsec::wireObj->endTransmission();
|
||||
Bsec::wireObj->requestFrom((int)devId, (int)length);
|
||||
for (i = 0; (i < length) && Bsec::wireObj->available(); i++) {
|
||||
regData[i] = Bsec::wireObj->read();
|
||||
}
|
||||
} else {
|
||||
rslt = -1;
|
||||
}
|
||||
return rslt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function for writing registers over I2C
|
||||
*/
|
||||
int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData,
|
||||
uint16_t length) {
|
||||
uint16_t i;
|
||||
int8_t rslt = 0;
|
||||
if (Bsec::wireObj) {
|
||||
Bsec::wireObj->beginTransmission(devId);
|
||||
Bsec::wireObj->write(regAddr);
|
||||
for (i = 0; i < length; i++) {
|
||||
Bsec::wireObj->write(regData[i]);
|
||||
}
|
||||
rslt = Bsec::wireObj->endTransmission();
|
||||
} else {
|
||||
rslt = -1;
|
||||
}
|
||||
|
||||
return rslt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback function for reading and writing registers over SPI
|
||||
*/
|
||||
int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData,
|
||||
uint16_t length) {
|
||||
int8_t rslt = 0;
|
||||
if (Bsec::spiObj) {
|
||||
Bsec::spiObj->beginTransaction(
|
||||
SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz
|
||||
|
||||
digitalWrite(devId, LOW);
|
||||
|
||||
Bsec::spiObj->transfer(
|
||||
regAddr); // Write the register address, ignore the return
|
||||
for (uint16_t i = 0; i < length; i++)
|
||||
regData[i] = Bsec::spiObj->transfer(regData[i]);
|
||||
|
||||
digitalWrite(devId, HIGH);
|
||||
Bsec::spiObj->endTransaction();
|
||||
} else {
|
||||
rslt = -1;
|
||||
}
|
||||
|
||||
return rslt;
|
||||
;
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names of the
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
|
||||
*
|
||||
* The information provided is believed to be accurate and reliable.
|
||||
* The copyright holder assumes no responsibility
|
||||
* for the consequences of use
|
||||
* of such information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use.
|
||||
* No license is granted by implication or otherwise under any patent or
|
||||
* patent rights of the copyright holder.
|
||||
*
|
||||
* @file bsec.h
|
||||
* @date 31 Jan 2018
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BSEC_CLASS_H
|
||||
#define BSEC_CLASS_H
|
||||
|
||||
/* Includes */
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
#include "SPI.h"
|
||||
#include "inc/bsec_datatypes.h"
|
||||
#include "inc/bsec_interface.h"
|
||||
#include "bme680/bme680.h"
|
||||
|
||||
/* BSEC class definition */
|
||||
class Bsec
|
||||
{
|
||||
public:
|
||||
/* Public variables */
|
||||
bsec_version_t version; // Stores the version of the BSEC algorithm
|
||||
int64_t nextCall; // Stores the time when the algorithm has to be called next in ms
|
||||
int8_t bme680Status; // Placeholder for the BME680 driver's error codes
|
||||
bsec_library_return_t status;
|
||||
float iaqEstimate, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity,
|
||||
staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage;
|
||||
uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAcccuracy;
|
||||
int64_t outputTimestamp; // Timestamp in ms of the output
|
||||
static TwoWire *wireObj;
|
||||
static SPIClass *spiObj;
|
||||
|
||||
/* Public APIs */
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
Bsec();
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
* @param devId : Device identifier parameter for the read/write interface functions
|
||||
* @param intf : Physical communication interface
|
||||
* @param read : Pointer to the read function
|
||||
* @param write : Pointer to the write function
|
||||
* @param idleTask : Pointer to the idling task
|
||||
*/
|
||||
void begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask);
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
* @param i2cAddr : I2C address
|
||||
* @param i2c : Pointer to the TwoWire object
|
||||
*/
|
||||
void begin(uint8_t i2cAddr, TwoWire &i2c);
|
||||
|
||||
/**
|
||||
* @brief Function to initialize the BSEC library and the BME680 sensor
|
||||
* @param chipSelect : SPI chip select
|
||||
* @param spi : Pointer to the SPIClass object
|
||||
*/
|
||||
void begin(uint8_t chipSelect, SPIClass &spi);
|
||||
|
||||
/**
|
||||
* @brief Function that sets the desired sensors and the sample rates
|
||||
* @param sensorList : The list of output sensors
|
||||
* @param nSensors : Number of outputs requested
|
||||
* @param sampleRate : The sample rate of requested sensors
|
||||
*/
|
||||
void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP);
|
||||
|
||||
/**
|
||||
* @brief Callback from the user to trigger reading of data from the BME680, process and store outputs
|
||||
* @return true if there are new outputs. false otherwise
|
||||
*/
|
||||
bool run(void);
|
||||
|
||||
/**
|
||||
* @brief Function to get the state of the algorithm to save to non-volatile memory
|
||||
* @param state : Pointer to a memory location that contains the state
|
||||
*/
|
||||
void getState(uint8_t *state);
|
||||
|
||||
/**
|
||||
* @brief Function to set the state of the algorithm from non-volatile memory
|
||||
* @param state : Pointer to a memory location that contains the state
|
||||
*/
|
||||
void setState(uint8_t *state);
|
||||
|
||||
/**
|
||||
* @brief Function to set the configuration of the algorithm from memory
|
||||
* @param state : Pointer to a memory location that contains the configuration
|
||||
*/
|
||||
void setConfig(const uint8_t *config);
|
||||
|
||||
/**
|
||||
* @brief Function to set the temperature offset
|
||||
* @param tempOffset : Temperature offset in degree Celsius
|
||||
*/
|
||||
void setTemperatureOffset(float tempOffset)
|
||||
{
|
||||
_tempOffset = tempOffset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function to calculate an int64_t timestamp in milliseconds
|
||||
*/
|
||||
int64_t getTimeMs(void);
|
||||
|
||||
/**
|
||||
* @brief Task that delays for a ms period of time
|
||||
* @param period : Period of time in ms
|
||||
*/
|
||||
static void delay_ms(uint32_t period);
|
||||
|
||||
/**
|
||||
* @brief Callback function for reading registers over I2C
|
||||
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||
* @param regAddr : Register address
|
||||
* @param regData : Pointer to the array containing the data to be read
|
||||
* @param length : Length of the array of data
|
||||
* @return Zero for success, non-zero otherwise
|
||||
*/
|
||||
static int8_t i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Callback function for writing registers over I2C
|
||||
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||
* @param regAddr : Register address
|
||||
* @param regData : Pointer to the array containing the data to be written
|
||||
* @param length : Length of the array of data
|
||||
* @return Zero for success, non-zero otherwise
|
||||
*/
|
||||
static int8_t i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Callback function for reading and writing registers over SPI
|
||||
* @param devId : Library agnostic parameter to identify the device to communicate with
|
||||
* @param regAddr : Register address
|
||||
* @param regData : Pointer to the array containing the data to be read or written
|
||||
* @param length : Length of the array of data
|
||||
* @return Zero for success, non-zero otherwise
|
||||
*/
|
||||
static int8_t spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length);
|
||||
|
||||
private:
|
||||
/* Private variables */
|
||||
struct bme680_dev _bme680;
|
||||
struct bme680_field_data _data;
|
||||
float _tempOffset;
|
||||
// Global variables to help create a millisecond timestamp that doesn't overflow every 51 days.
|
||||
// If it overflows, it will have a negative value. Something that should never happen.
|
||||
uint32_t millisOverflowCounter;
|
||||
uint32_t lastTime;
|
||||
|
||||
/* Private APIs */
|
||||
/**
|
||||
* @brief Get the version of the BSEC library
|
||||
*/
|
||||
void getVersion(void);
|
||||
|
||||
/**
|
||||
* @brief Read data from the BME680 and process it
|
||||
* @param currTimeNs: Current time in ns
|
||||
* @param bme680Settings: BME680 sensor's settings
|
||||
* @return true if there are new outputs. false otherwise
|
||||
*/
|
||||
bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings);
|
||||
|
||||
/**
|
||||
* @brief Set the BME680 sensor's configuration
|
||||
* @param bme680Settings: Settings to configure the BME680
|
||||
* @return BME680 return code. BME680_OK for success, failure otherwise
|
||||
*/
|
||||
int8_t setBme680Config(bsec_bme_settings_t bme680Settings);
|
||||
|
||||
/**
|
||||
* @brief Common code for the begin function
|
||||
*/
|
||||
void beginCommon(void);
|
||||
|
||||
/**
|
||||
* @brief Function to zero the outputs
|
||||
*/
|
||||
void zeroOutputs(void);
|
||||
};
|
||||
|
||||
#endif
|
@ -1,488 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015, 2016, 2017 Robert Bosch. All Rights Reserved.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* Common:
|
||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
||||
*
|
||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
||||
* Sensortec for all costs in connection with such claims.
|
||||
*
|
||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
||||
*
|
||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
||||
* samples.
|
||||
*
|
||||
* Special:
|
||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
||||
* application work. The Software and Information is subject to the following terms and conditions:
|
||||
*
|
||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
||||
* proper experience or training.
|
||||
*
|
||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
||||
* purpose.
|
||||
*
|
||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
||||
* otherwise stipulated in mandatory applicable law.
|
||||
*
|
||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
||||
* subject to change without notice.
|
||||
*
|
||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
||||
* Bosch Sensortec.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file bsec_datatypes.h
|
||||
*
|
||||
* @brief
|
||||
* Contains the data types used by BSEC
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BSEC_DATATYPES_H__
|
||||
#define __BSEC_DATATYPES_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @addtogroup bsec_interface BSEC C Interface
|
||||
* @{*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define BSEC_MAX_WORKBUFFER_SIZE (2048) /*!< Maximum size (in bytes) of the work buffer */
|
||||
#define BSEC_MAX_PHYSICAL_SENSOR (8) /*!< Number of physical sensors that need allocated space before calling bsec_update_subscription() */
|
||||
#define BSEC_MAX_PROPERTY_BLOB_SIZE (454) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_configuration() */
|
||||
#define BSEC_MAX_STATE_BLOB_SIZE (139) /*!< Maximum size (in bytes) of the data blobs returned by bsec_get_state()*/
|
||||
#define BSEC_SAMPLE_RATE_DISABLED (65535.0f) /*!< Sample rate of a disabled sensor */
|
||||
#define BSEC_SAMPLE_RATE_ULP (0.0033333f) /*!< Sample rate in case of Ultra Low Power Mode */
|
||||
#define BSEC_SAMPLE_RATE_LP (0.33333f) /*!< Sample rate in case of Low Power Mode */
|
||||
#define BSEC_SAMPLE_RATE_ULP_MEASUREMENT_ON_DEMAND (0.0f) /*!< Input value used to trigger an extra measurment (ULP plus) */
|
||||
|
||||
#define BSEC_PROCESS_PRESSURE (1 << (BSEC_INPUT_PRESSURE-1)) /*!< process_data bitfield constant for pressure @sa bsec_bme_settings_t */
|
||||
#define BSEC_PROCESS_TEMPERATURE (1 << (BSEC_INPUT_TEMPERATURE-1)) /*!< process_data bitfield constant for temperature @sa bsec_bme_settings_t */
|
||||
#define BSEC_PROCESS_HUMIDITY (1 << (BSEC_INPUT_HUMIDITY-1)) /*!< process_data bitfield constant for humidity @sa bsec_bme_settings_t */
|
||||
#define BSEC_PROCESS_GAS (1 << (BSEC_INPUT_GASRESISTOR-1)) /*!< process_data bitfield constant for gas sensor @sa bsec_bme_settings_t */
|
||||
#define BSEC_NUMBER_OUTPUTS (14) /*!< Number of outputs, depending on solution */
|
||||
#define BSEC_OUTPUT_INCLUDED (1210863) /*!< bitfield that indicates which outputs are included in the solution */
|
||||
|
||||
/*!
|
||||
* @brief Enumeration for input (physical) sensors.
|
||||
*
|
||||
* Used to populate bsec_input_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs
|
||||
* returned in the parameter required_sensor_settings of bsec_update_subscription().
|
||||
*
|
||||
* @sa bsec_sensor_configuration_t @sa bsec_input_t
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* @brief Pressure sensor output of BMExxx [Pa]
|
||||
*/
|
||||
BSEC_INPUT_PRESSURE = 1,
|
||||
|
||||
/**
|
||||
* @brief Humidity sensor output of BMExxx [%]
|
||||
*
|
||||
* @note Relative humidity strongly depends on the temperature (it is measured at). It may require a conversion to
|
||||
* the temperature outside of the device.
|
||||
*
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*/
|
||||
BSEC_INPUT_HUMIDITY = 2,
|
||||
|
||||
/**
|
||||
* @brief Temperature sensor output of BMExxx [degrees Celsius]
|
||||
*
|
||||
* @note The BME680 is factory trimmed, thus the temperature sensor of the BME680 is very accurate.
|
||||
* The temperature value is a very local measurement value and can be influenced by external heat sources.
|
||||
*
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*/
|
||||
BSEC_INPUT_TEMPERATURE = 3,
|
||||
|
||||
/**
|
||||
* @brief Gas sensor resistance output of BMExxx [Ohm]
|
||||
*
|
||||
* The resistance value changes due to varying VOC concentrations (the higher the concentration of reducing VOCs,
|
||||
* the lower the resistance and vice versa).
|
||||
*/
|
||||
BSEC_INPUT_GASRESISTOR = 4, /*!< */
|
||||
|
||||
/**
|
||||
* @brief Additional input for device heat compensation
|
||||
*
|
||||
* IAQ solution: The value is subtracted from ::BSEC_INPUT_TEMPERATURE to compute
|
||||
* ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE.
|
||||
*
|
||||
* ALL solution: Generic heat source 1
|
||||
*
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*/
|
||||
BSEC_INPUT_HEATSOURCE = 14,
|
||||
|
||||
/**
|
||||
* @brief Additional input for device heat compensation 8
|
||||
*
|
||||
* Generic heat source 8
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Additional input that disables baseline tracker
|
||||
*
|
||||
* 0 - Normal
|
||||
* 1 - Event 1
|
||||
* 2 - Event 2
|
||||
*/
|
||||
BSEC_INPUT_DISABLE_BASELINE_TRACKER = 23,
|
||||
|
||||
} bsec_physical_sensor_t;
|
||||
|
||||
/*!
|
||||
* @brief Enumeration for output (virtual) sensors
|
||||
*
|
||||
* Used to populate bsec_output_t::sensor_id. It is also used in bsec_sensor_configuration_t::sensor_id structs
|
||||
* passed in the parameter requested_virtual_sensors of bsec_update_subscription().
|
||||
*
|
||||
* @sa bsec_sensor_configuration_t @sa bsec_output_t
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/**
|
||||
* @brief Indoor-air-quality estimate [0-500]
|
||||
*
|
||||
* Indoor-air-quality (IAQ) gives an indication of the relative change in ambient TVOCs detected by BME680.
|
||||
*
|
||||
* @note The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air). During operation, algorithms
|
||||
* automatically calibrate and adapt themselves to the typical environments where the sensor is operated
|
||||
* (e.g., home, workplace, inside a car, etc.).This automatic background calibration ensures that users experience
|
||||
* consistent IAQ performance. The calibration process considers the recent measurement history (typ. up to four
|
||||
* days) to ensure that IAQ=25 corresponds to typical good air and IAQ=250 indicates typical polluted air.
|
||||
*/
|
||||
BSEC_OUTPUT_IAQ = 1,
|
||||
BSEC_OUTPUT_STATIC_IAQ = 2, /*!< Unscaled indoor-air-quality estimate */
|
||||
BSEC_OUTPUT_CO2_EQUIVALENT = 3, /*!< co2 equivalent estimate [ppm] */
|
||||
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, /*!< breath VOC concentration estimate [ppm] */
|
||||
|
||||
/**
|
||||
* @brief Temperature sensor signal [degrees Celsius]
|
||||
*
|
||||
* Temperature directly measured by BME680 in degree Celsius.
|
||||
*
|
||||
* @note This value is cross-influenced by the sensor heating and device specific heating.
|
||||
*/
|
||||
BSEC_OUTPUT_RAW_TEMPERATURE = 6,
|
||||
|
||||
/**
|
||||
* @brief Pressure sensor signal [Pa]
|
||||
*
|
||||
* Pressure directly measured by the BME680 in Pa.
|
||||
*/
|
||||
BSEC_OUTPUT_RAW_PRESSURE = 7,
|
||||
|
||||
/**
|
||||
* @brief Relative humidity sensor signal [%]
|
||||
*
|
||||
* Relative humidity directly measured by the BME680 in %.
|
||||
*
|
||||
* @note This value is cross-influenced by the sensor heating and device specific heating.
|
||||
*/
|
||||
BSEC_OUTPUT_RAW_HUMIDITY = 8,
|
||||
|
||||
/**
|
||||
* @brief Gas sensor signal [Ohm]
|
||||
*
|
||||
* Gas resistance measured directly by the BME680 in Ohm.The resistance value changes due to varying VOC
|
||||
* concentrations (the higher the concentration of reducing VOCs, the lower the resistance and vice versa).
|
||||
*/
|
||||
BSEC_OUTPUT_RAW_GAS = 9,
|
||||
|
||||
/**
|
||||
* @brief Gas sensor stabilization status [boolean]
|
||||
*
|
||||
* Indicates initial stabilization status of the gas sensor element: stabilization is ongoing (0) or stabilization
|
||||
* is finished (1).
|
||||
*/
|
||||
BSEC_OUTPUT_STABILIZATION_STATUS = 12,
|
||||
|
||||
/**
|
||||
* @brief Gas sensor run-in status [boolean]
|
||||
*
|
||||
* Indicates power-on stabilization status of the gas sensor element: stabilization is ongoing (0) or stabilization
|
||||
* is finished (1).
|
||||
*/
|
||||
BSEC_OUTPUT_RUN_IN_STATUS = 13,
|
||||
|
||||
/**
|
||||
* @brief Sensor heat compensated temperature [degrees Celsius]
|
||||
*
|
||||
* Temperature measured by BME680 which is compensated for the influence of sensor (heater) in degree Celsius.
|
||||
* The self heating introduced by the heater is depending on the sensor operation mode and the sensor supply voltage.
|
||||
*
|
||||
*
|
||||
* @note IAQ solution: In addition, the temperature output can be compensated by an user defined value
|
||||
* (::BSEC_INPUT_HEATSOURCE in degrees Celsius), which represents the device specific self-heating.
|
||||
*
|
||||
* Thus, the value is calculated as follows:
|
||||
* * IAQ solution: ```BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage) - ::BSEC_INPUT_HEATSOURCE```
|
||||
* * other solutions: ```::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = ::BSEC_INPUT_TEMPERATURE - function(sensor operation mode, sensor supply voltage)```
|
||||
*
|
||||
* The self-heating in operation mode BSEC_SAMPLE_RATE_ULP is negligible.
|
||||
* The self-heating in operation mode BSEC_SAMPLE_RATE_LP is supported for 1.8V by default (no config file required). If the BME680 sensor supply voltage is 3.3V, the IoT_LP_3_3V.config shall be used.
|
||||
*/
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14,
|
||||
|
||||
/**
|
||||
* @brief Sensor heat compensated humidity [%]
|
||||
*
|
||||
* Relative measured by BME680 which is compensated for the influence of sensor (heater) in %.
|
||||
*
|
||||
* It converts the ::BSEC_INPUT_HUMIDITY from temperature ::BSEC_INPUT_TEMPERATURE to temperature
|
||||
* ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE.
|
||||
*
|
||||
* @note IAQ solution: If ::BSEC_INPUT_HEATSOURCE is used for device specific temperature compensation, it will be
|
||||
* effective for ::BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY too.
|
||||
*/
|
||||
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15,
|
||||
|
||||
BSEC_OUTPUT_COMPENSATED_GAS = 18, /*!< Reserved internal debug output */
|
||||
BSEC_OUTPUT_GAS_PERCENTAGE = 21 /*!< percentage of min and max filtered gas value [%] */
|
||||
} bsec_virtual_sensor_t;
|
||||
|
||||
/*!
|
||||
* @brief Enumeration for function return codes
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSEC_OK = 0, /*!< Function execution successful */
|
||||
BSEC_E_DOSTEPS_INVALIDINPUT = -1, /*!< Input (physical) sensor id passed to bsec_do_steps() is not in the valid range or not valid for requested virtual sensor */
|
||||
BSEC_E_DOSTEPS_VALUELIMITS = -2, /*!< Value of input (physical) sensor signal passed to bsec_do_steps() is not in the valid range */
|
||||
BSEC_E_DOSTEPS_DUPLICATEINPUT = -6, /*!< Duplicate input (physical) sensor ids passed as input to bsec_do_steps() */
|
||||
BSEC_I_DOSTEPS_NOOUTPUTSRETURNABLE = 2, /*!< No memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs == 0 */
|
||||
BSEC_W_DOSTEPS_EXCESSOUTPUTS = 3, /*!< Not enough memory allocated to hold return values from bsec_do_steps(), i.e., n_outputs < maximum number of requested output (virtual) sensors */
|
||||
BSEC_W_DOSTEPS_TSINTRADIFFOUTOFRANGE = 4, /*!< Duplicate timestamps passed to bsec_do_steps() */
|
||||
BSEC_E_SU_WRONGDATARATE = -10, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is zero */
|
||||
BSEC_E_SU_SAMPLERATELIMITS = -12, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not match with the sampling rate allowed for that sensor */
|
||||
BSEC_E_SU_DUPLICATEGATE = -13, /*!< Duplicate output (virtual) sensor ids requested through bsec_update_subscription() */
|
||||
BSEC_E_SU_INVALIDSAMPLERATE = -14, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() does not fall within the global minimum and maximum sampling rates */
|
||||
BSEC_E_SU_GATECOUNTEXCEEDSARRAY = -15, /*!< Not enough memory allocated to hold returned input (physical) sensor data from bsec_update_subscription(), i.e., n_required_sensor_settings < #BSEC_MAX_PHYSICAL_SENSOR */
|
||||
BSEC_E_SU_SAMPLINTVLINTEGERMULT = -16, /*!< The sample_rate of the requested output (virtual) sensor passed to bsec_update_subscription() is not correct */
|
||||
BSEC_E_SU_MULTGASSAMPLINTVL = -17, /*!< The sample_rate of the requested output (virtual), which requires the gas sensor, is not equal to the sample_rate that the gas sensor is being operated */
|
||||
BSEC_E_SU_HIGHHEATERONDURATION = -18, /*!< The duration of one measurement is longer than the requested sampling interval */
|
||||
BSEC_W_SU_UNKNOWNOUTPUTGATE = 10, /*!< Output (virtual) sensor id passed to bsec_update_subscription() is not in the valid range; e.g., n_requested_virtual_sensors > actual number of output (virtual) sensors requested */
|
||||
BSEC_W_SU_MODINNOULP = 11, /*!< ULP plus can not be requested in non-ulp mode */ /*MOD_ONLY*/
|
||||
BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12, /*!< No output (virtual) sensor data were requested via bsec_update_subscription() */
|
||||
BSEC_E_PARSE_SECTIONEXCEEDSWORKBUFFER = -32, /*!< n_work_buffer_size passed to bsec_set_[configuration/state]() not sufficient */
|
||||
BSEC_E_CONFIG_FAIL = -33, /*!< Configuration failed */
|
||||
BSEC_E_CONFIG_VERSIONMISMATCH = -34, /*!< Version encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current version */
|
||||
BSEC_E_CONFIG_FEATUREMISMATCH = -35, /*!< Enabled features encoded in serialized_[settings/state] passed to bsec_set_[configuration/state]() does not match with current library implementation */
|
||||
BSEC_E_CONFIG_CRCMISMATCH = -36, /*!< serialized_[settings/state] passed to bsec_set_[configuration/state]() is corrupted */
|
||||
BSEC_E_CONFIG_EMPTY = -37, /*!< n_serialized_[settings/state] passed to bsec_set_[configuration/state]() is to short to be valid */
|
||||
BSEC_E_CONFIG_INSUFFICIENTWORKBUFFER = -38, /*!< Provided work_buffer is not large enough to hold the desired string */
|
||||
BSEC_E_CONFIG_INVALIDSTRINGSIZE = -40, /*!< String size encoded in configuration/state strings passed to bsec_set_[configuration/state]() does not match with the actual string size n_serialized_[settings/state] passed to these functions */
|
||||
BSEC_E_CONFIG_INSUFFICIENTBUFFER = -41, /*!< String buffer insufficient to hold serialized data from BSEC library */
|
||||
BSEC_E_SET_INVALIDCHANNELIDENTIFIER = -100, /*!< Internal error code, size of work buffer in setConfig must be set to BSEC_MAX_WORKBUFFER_SIZE */
|
||||
BSEC_E_SET_INVALIDLENGTH = -104, /*!< Internal error code */
|
||||
BSEC_W_SC_CALL_TIMING_VIOLATION = 100, /*!< Difference between actual and defined sampling intervals of bsec_sensor_control() greater than allowed */
|
||||
BSEC_W_SC_MODEXCEEDULPTIMELIMIT = 101, /*!< ULP plus is not allowed because an ULP measurement just took or will take place */ /*MOD_ONLY*/
|
||||
BSEC_W_SC_MODINSUFFICIENTWAITTIME = 102 /*!< ULP plus is not allowed because not sufficient time passed since last ULP plus */ /*MOD_ONLY*/
|
||||
} bsec_library_return_t;
|
||||
|
||||
/*!
|
||||
* @brief Structure containing the version information
|
||||
*
|
||||
* Please note that configuration and state strings are coded to a specific version and will not be accepted by other
|
||||
* versions of BSEC.
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t major; /**< @brief Major version */
|
||||
uint8_t minor; /**< @brief Minor version */
|
||||
uint8_t major_bugfix; /**< @brief Major bug fix version */
|
||||
uint8_t minor_bugfix; /**< @brief Minor bug fix version */
|
||||
} bsec_version_t;
|
||||
|
||||
/*!
|
||||
* @brief Structure describing an input sample to the library
|
||||
*
|
||||
* Each input sample is provided to BSEC as an element in a struct array of this type. Timestamps must be provided
|
||||
* in nanosecond resolution. Moreover, duplicate timestamps for subsequent samples are not allowed and will results in
|
||||
* an error code being returned from bsec_do_steps().
|
||||
*
|
||||
* The meaning unit of the signal field are determined by the bsec_input_t::sensor_id field content. Possible
|
||||
* bsec_input_t::sensor_id values and and their meaning are described in ::bsec_physical_sensor_t.
|
||||
*
|
||||
* @sa bsec_physical_sensor_t
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* @brief Time stamp in nanosecond resolution [ns]
|
||||
*
|
||||
* Timestamps must be provided as non-repeating and increasing values. They can have their 0-points at system start or
|
||||
* at a defined wall-clock time (e.g., 01-Jan-1970 00:00:00)
|
||||
*/
|
||||
int64_t time_stamp;
|
||||
float signal; /*!< @brief Signal sample in the unit defined for the respective sensor_id @sa bsec_physical_sensor_t */
|
||||
uint8_t signal_dimensions; /*!< @brief Signal dimensions (reserved for future use, shall be set to 1) */
|
||||
uint8_t sensor_id; /*!< @brief Identifier of physical sensor @sa bsec_physical_sensor_t */
|
||||
} bsec_input_t;
|
||||
|
||||
/*!
|
||||
* @brief Structure describing an output sample of the library
|
||||
*
|
||||
* Each output sample is returned from BSEC by populating the element of a struct array of this type. The contents of
|
||||
* the signal field is defined by the supplied bsec_output_t::sensor_id. Possible output
|
||||
* bsec_output_t::sensor_id values are defined in ::bsec_virtual_sensor_t.
|
||||
*
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int64_t time_stamp; /*!< @brief Time stamp in nanosecond resolution as provided as input [ns] */
|
||||
float signal; /*!< @brief Signal sample in the unit defined for the respective bsec_output_t::sensor_id @sa bsec_virtual_sensor_t */
|
||||
uint8_t signal_dimensions; /*!< @brief Signal dimensions (reserved for future use, shall be set to 1) */
|
||||
uint8_t sensor_id; /*!< @brief Identifier of virtual sensor @sa bsec_virtual_sensor_t */
|
||||
|
||||
/**
|
||||
* @brief Accuracy status 0-3
|
||||
*
|
||||
* Some virtual sensors provide a value in the accuracy field. If this is the case, the meaning of the field is as
|
||||
* follows:
|
||||
*
|
||||
* | Name | Value | Accuracy description |
|
||||
* |----------------------------|-------|-------------------------------------------------------------|
|
||||
* | UNRELIABLE | 0 | Sensor data is unreliable, the sensor must be calibrated |
|
||||
* | LOW_ACCURACY | 1 | Low accuracy, sensor should be calibrated |
|
||||
* | MEDIUM_ACCURACY | 2 | Medium accuracy, sensor calibration may improve performance |
|
||||
* | HIGH_ACCURACY | 3 | High accuracy |
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* - Ambient temperature accuracy is derived from change in the temperature in 1 minute.
|
||||
*
|
||||
* | Virtual sensor | Value | Accuracy description |
|
||||
* |--------------------- |-------|------------------------------------------------------------------------------|
|
||||
* | Ambient temperature | 0 | The difference in ambient temperature is greater than 4 degree in one minute |
|
||||
* | | 1 | The difference in ambient temperature is less than 4 degree in one minute |
|
||||
* | | 2 | The difference in ambient temperature is less than 3 degree in one minute |
|
||||
* | | 3 | The difference in ambient temperature is less than 2 degree in one minute |
|
||||
*
|
||||
* - IAQ accuracy indicator will notify the user when she/he should initiate a calibration process. Calibration is
|
||||
* performed automatically in the background if the sensor is exposed to clean and polluted air for approximately
|
||||
* 30 minutes each.
|
||||
*
|
||||
* | Virtual sensor | Value | Accuracy description |
|
||||
* |----------------------------|-------|-----------------------------------------------------------------|
|
||||
* | IAQ | 0 | The sensor is not yet stabilized or in a run-in status |
|
||||
* | | 1 | Calibration required |
|
||||
* | | 2 | Calibration on-going |
|
||||
* | | 3 | Calibration is done, now IAQ estimate achieves best performance |
|
||||
*/
|
||||
uint8_t accuracy;
|
||||
} bsec_output_t;
|
||||
|
||||
/*!
|
||||
* @brief Structure describing sample rate of physical/virtual sensors
|
||||
*
|
||||
* This structure is used together with bsec_update_subscription() to enable BSEC outputs and to retrieve information
|
||||
* about the sample rates used for BSEC inputs.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* @brief Sample rate of the virtual or physical sensor in Hertz [Hz]
|
||||
*
|
||||
* Only supported sample rates are allowed.
|
||||
*/
|
||||
float sample_rate;
|
||||
|
||||
/**
|
||||
* @brief Identifier of the virtual or physical sensor
|
||||
*
|
||||
* The meaning of this field changes depending on whether the structs are as the requested_virtual_sensors argument
|
||||
* to bsec_update_subscription() or as the required_sensor_settings argument.
|
||||
*
|
||||
* | bsec_update_subscription() argument | sensor_id field interpretation |
|
||||
* |-------------------------------------|--------------------------------|
|
||||
* | requested_virtual_sensors | ::bsec_virtual_sensor_t |
|
||||
* | required_sensor_settings | ::bsec_physical_sensor_t |
|
||||
*
|
||||
* @sa bsec_physical_sensor_t
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*/
|
||||
uint8_t sensor_id;
|
||||
} bsec_sensor_configuration_t;
|
||||
|
||||
/*!
|
||||
* @brief Structure returned by bsec_sensor_control() to configure BMExxx sensor
|
||||
*
|
||||
* This structure contains settings that must be used to configure the BMExxx to perform a forced-mode measurement.
|
||||
* A measurement should only be executed if bsec_bme_settings_t::trigger_measurement is 1. If so, the oversampling
|
||||
* settings for temperature, humidity, and pressure should be set to the provided settings provided in
|
||||
* bsec_bme_settings_t::temperature_oversampling, bsec_bme_settings_t::humidity_oversampling, and
|
||||
* bsec_bme_settings_t::pressure_oversampling, respectively.
|
||||
*
|
||||
* In case of bsec_bme_settings_t::run_gas = 1, the gas sensor must be enabled with the provided
|
||||
* bsec_bme_settings_t::heater_temperature and bsec_bme_settings_t::heating_duration settings.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int64_t next_call; /*!< @brief Time stamp of the next call of the sensor_control*/
|
||||
uint32_t process_data; /*!< @brief Bit field describing which data is to be passed to bsec_do_steps() @sa BSEC_PROCESS_* */
|
||||
uint16_t heater_temperature; /*!< @brief Heating temperature [degrees Celsius] */
|
||||
uint16_t heating_duration; /*!< @brief Heating duration [ms] */
|
||||
uint8_t run_gas; /*!< @brief Enable gas measurements [0/1] */
|
||||
uint8_t pressure_oversampling; /*!< @brief Pressure oversampling settings [0-5] */
|
||||
uint8_t temperature_oversampling; /*!< @brief Temperature oversampling settings [0-5] */
|
||||
uint8_t humidity_oversampling; /*!< @brief Humidity oversampling settings [0-5] */
|
||||
uint8_t trigger_measurement; /*!< @brief Trigger a forced measurement with these settings now [0/1] */
|
||||
} bsec_bme_settings_t;
|
||||
|
||||
/* internal defines and backward compatibility */
|
||||
#define BSEC_STRUCT_NAME Bsec /*!< Internal struct name */
|
||||
|
||||
/*@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,564 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015, 2016, 2017 Robert Bosch. All Rights Reserved.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* Common:
|
||||
* Bosch Sensortec products are developed for the consumer goods industry. They may only be used
|
||||
* within the parameters of the respective valid product data sheet. Bosch Sensortec products are
|
||||
* provided with the express understanding that there is no warranty of fitness for a particular purpose.
|
||||
* They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
|
||||
* that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
|
||||
* Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
|
||||
* The resale and/or use of products are at the purchasers own risk and his own responsibility. The
|
||||
* examination of fitness for the intended use is the sole responsibility of the Purchaser.
|
||||
*
|
||||
* The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
|
||||
* incidental, or consequential damages, arising from any product use not covered by the parameters of
|
||||
* the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
|
||||
* Sensortec for all costs in connection with such claims.
|
||||
*
|
||||
* The purchaser must monitor the market for the purchased products, particularly with regard to
|
||||
* product safety and inform Bosch Sensortec without delay of all security relevant incidents.
|
||||
*
|
||||
* Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
|
||||
* technical specifications of the product series. They are therefore not intended or fit for resale to third
|
||||
* parties or for use in end products. Their sole purpose is internal client testing. The testing of an
|
||||
* engineering sample may in no way replace the testing of a product series. Bosch Sensortec
|
||||
* assumes no liability for the use of engineering samples. By accepting the engineering samples, the
|
||||
* Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
|
||||
* samples.
|
||||
*
|
||||
* Special:
|
||||
* This software module (hereinafter called "Software") and any information on application-sheets
|
||||
* (hereinafter called "Information") is provided free of charge for the sole purpose to support your
|
||||
* application work. The Software and Information is subject to the following terms and conditions:
|
||||
*
|
||||
* The Software is specifically designed for the exclusive use for Bosch Sensortec products by
|
||||
* personnel who have special experience and training. Do not use this Software if you do not have the
|
||||
* proper experience or training.
|
||||
*
|
||||
* This Software package is provided `` as is `` and without any expressed or implied warranties,
|
||||
* including without limitation, the implied warranties of merchantability and fitness for a particular
|
||||
* purpose.
|
||||
*
|
||||
* Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
|
||||
* of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
|
||||
* representatives and agents shall not be liable for any direct or indirect damages or injury, except as
|
||||
* otherwise stipulated in mandatory applicable law.
|
||||
*
|
||||
* The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
|
||||
* responsibility for the consequences of use of such Information nor for any infringement of patents or
|
||||
* other rights of third parties which may result from its use. No license is granted by implication or
|
||||
* otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
|
||||
* subject to change without notice.
|
||||
*
|
||||
* It is not allowed to deliver the source code of the Software to any third party without permission of
|
||||
* Bosch Sensortec.
|
||||
*
|
||||
*/
|
||||
/*!
|
||||
*
|
||||
* @file bsec_interface.h
|
||||
*
|
||||
* @brief
|
||||
* Contains the API for BSEC
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __BSEC_INTERFACE_H__
|
||||
#define __BSEC_INTERFACE_H__
|
||||
|
||||
#include "bsec_datatypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*! @addtogroup bsec_interface BSEC C Interface
|
||||
* @brief Interfaces of BSEC signal processing library
|
||||
*
|
||||
* ### Interface usage
|
||||
*
|
||||
* The following provides a short overview on the typical operation sequence for BSEC.
|
||||
*
|
||||
* - Initialization of the library
|
||||
*
|
||||
* | Steps | Function |
|
||||
* |---------------------------------------------------------------------|--------------------------|
|
||||
* | Initialization of library | bsec_init() |
|
||||
* | Update configuration settings (optional) | bsec_set_configuration() |
|
||||
* | Restore the state of the library (optional) | bsec_set_state() |
|
||||
*
|
||||
*
|
||||
* - The following function is called to enable output signals and define their sampling rate / operation mode.
|
||||
*
|
||||
* | Steps | Function |
|
||||
* |---------------------------------------------|----------------------------|
|
||||
* | Enable library outputs with specified mode | bsec_update_subscription() |
|
||||
*
|
||||
*
|
||||
* - This table describes the main processing loop.
|
||||
*
|
||||
* | Steps | Function |
|
||||
* |-------------------------------------------|----------------------------------|
|
||||
* | Retrieve sensor settings to be used | bsec_sensor_control() |
|
||||
* | Configure sensor and trigger measurement | See BME680 API and example codes |
|
||||
* | Read results from sensor | See BME680 API and example codes |
|
||||
* | Perform signal processing | bsec_do_steps() |
|
||||
*
|
||||
*
|
||||
* - Before shutting down the system, the current state of BSEC can be retrieved and can then be used during
|
||||
* re-initialization to continue processing.
|
||||
*
|
||||
* | Steps | Function |
|
||||
* |----------------------------------------|-------------------|
|
||||
* | To retrieve the current library state | bsec_get_state() |
|
||||
*
|
||||
*
|
||||
*
|
||||
* ### Configuration and state
|
||||
*
|
||||
* Values of variables belonging to a BSEC instance are divided into two groups:
|
||||
* - Values **not updated by processing** of signals belong to the **configuration group**. If available, BSEC can be
|
||||
* configured before use with a customer specific configuration string.
|
||||
* - Values **updated during processing** are member of the **state group**. Saving and restoring of the state of BSEC
|
||||
* is necessary to maintain previously estimated sensor models and baseline information which is important for best
|
||||
* performance of the gas sensor outputs.
|
||||
*
|
||||
* @note BSEC library consists of adaptive algorithms which models the gas sensor which improves its performance over
|
||||
* the time. These will be lost if library is initialized due to system reset. In order to avoid this situation
|
||||
* library state shall be stored in non volatile memory so that it can be loaded after system reset.
|
||||
*
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Return the version information of BSEC library
|
||||
*
|
||||
* @param [out] bsec_version_p pointer to struct which is to be populated with the version information
|
||||
*
|
||||
* @return Zero if successful, otherwise an error code
|
||||
*
|
||||
* See also: bsec_version_t
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
bsec_version_t version;
|
||||
bsec_get_version(&version);
|
||||
printf("BSEC version: %d.%d.%d.%d",version.major, version.minor, version.major_bugfix, version.minor_bugfix);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_get_version(bsec_version_t * bsec_version_p);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Initialize the library
|
||||
*
|
||||
* Initialization and reset of BSEC is performed by calling bsec_init(). Calling this function sets up the relation
|
||||
* among all internal modules, initializes run-time dependent library states and resets the configuration and state
|
||||
* of all BSEC signal processing modules to defaults.
|
||||
*
|
||||
* Before any further use, the library must be initialized. This ensure that all memory and states are in defined
|
||||
* conditions prior to processing any data.
|
||||
*
|
||||
* @return Zero if successful, otherwise an error code
|
||||
*
|
||||
\code{.c}
|
||||
|
||||
// Initialize BSEC library before further use
|
||||
bsec_init();
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_init(void);
|
||||
|
||||
/*!
|
||||
* @brief Subscribe to library virtual sensors outputs
|
||||
*
|
||||
* Use bsec_update_subscription() to instruct BSEC which of the processed output signals are requested at which sample rates.
|
||||
* See ::bsec_virtual_sensor_t for available library outputs.
|
||||
*
|
||||
* Based on the requested virtual sensors outputs, BSEC will provide information about the required physical sensor input signals
|
||||
* (see ::bsec_physical_sensor_t) with corresponding sample rates. This information is purely informational as bsec_sensor_control()
|
||||
* will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to BSEC_SAMPLE_RATE_DISABLED.
|
||||
*
|
||||
* The subscription update using bsec_update_subscription() is apart from the signal processing one of the the most
|
||||
* important functions. It allows to enable the desired library outputs. The function determines which physical input
|
||||
* sensor signals are required at which sample rate to produce the virtual output sensor signals requested by the user.
|
||||
* When this function returns with success, the requested outputs are called subscribed. A very important feature is the
|
||||
* retaining of already subscribed outputs. Further outputs can be requested or disabled both individually and
|
||||
* group-wise in addition to already subscribed outputs without changing them unless a change of already subscribed
|
||||
* outputs is requested.
|
||||
*
|
||||
* @note The state of the library concerning the subscribed outputs cannot be retained among reboots.
|
||||
*
|
||||
* The interface of bsec_update_subscription() requires the usage of arrays of sensor configuration structures.
|
||||
* Such a structure has the fields sensor identifier and sample rate. These fields have the properties:
|
||||
* - Output signals of virtual sensors must be requested using unique identifiers (Member of ::bsec_virtual_sensor_t)
|
||||
* - Different sets of identifiers are available for inputs of physical sensors and outputs of virtual sensors
|
||||
* - Identifiers are unique values defined by the library, not from external
|
||||
* - Sample rates must be provided as value of
|
||||
* - An allowed sample rate for continuously sampled signals
|
||||
* - 65535.0f (BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs
|
||||
*
|
||||
* @note The same sensor identifiers are also used within the functions bsec_do_steps().
|
||||
*
|
||||
* The usage principles of bsec_update_subscription() are:
|
||||
* - Differential updates (i.e., only asking for outputs that the user would like to change) is supported.
|
||||
* - Invalid requests of outputs are ignored. Also if one of the requested outputs is unavailable, all the requests
|
||||
* are ignored. At the same time, a warning is returned.
|
||||
* - To disable BSEC, all outputs shall be turned off. Only enabled (subscribed) outputs have to be disabled while
|
||||
* already disabled outputs do not have to be disabled explicitly.
|
||||
*
|
||||
* @param[in] requested_virtual_sensors Pointer to array of requested virtual sensor (output) configurations for the library
|
||||
* @param[in] n_requested_virtual_sensors Number of virtual sensor structs pointed by requested_virtual_sensors
|
||||
* @param[out] required_sensor_settings Pointer to array of required physical sensor configurations for the library
|
||||
* @param[in,out] n_required_sensor_settings [in] Size of allocated required_sensor_settings array, [out] number of sensor configurations returned
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
* @sa bsec_sensor_configuration_t
|
||||
* @sa bsec_physical_sensor_t
|
||||
* @sa bsec_virtual_sensor_t
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Change 3 virtual sensors (switch IAQ and raw temperature -> on / pressure -> off)
|
||||
bsec_sensor_configuration_t requested_virtual_sensors[3];
|
||||
uint8_t n_requested_virtual_sensors = 3;
|
||||
|
||||
requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
|
||||
requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP;
|
||||
requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
|
||||
requested_virtual_sensors[1].sample_rate = BSEC_SAMPLE_RATE_ULP;
|
||||
requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
|
||||
requested_virtual_sensors[2].sample_rate = BSEC_SAMPLE_RATE_DISABLED;
|
||||
|
||||
// Allocate a struct for the returned physical sensor settings
|
||||
bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
|
||||
uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
|
||||
|
||||
// Call bsec_update_subscription() to enable/disable the requested virtual sensors
|
||||
bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings, &n_required_sensor_settings);
|
||||
\endcode
|
||||
*
|
||||
*/
|
||||
bsec_library_return_t bsec_update_subscription(const bsec_sensor_configuration_t * const requested_virtual_sensors,
|
||||
const uint8_t n_requested_virtual_sensors, bsec_sensor_configuration_t * required_sensor_settings,
|
||||
uint8_t * n_required_sensor_settings);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Main signal processing function of BSEC
|
||||
*
|
||||
*
|
||||
* Processing of the input signals and returning of output samples is performed by bsec_do_steps().
|
||||
* - The samples of all library inputs must be passed with unique identifiers representing the input signals from
|
||||
* physical sensors where the order of these inputs can be chosen arbitrary. However, all input have to be provided
|
||||
* within the same time period as they are read. A sequential provision to the library might result in undefined
|
||||
* behavior.
|
||||
* - The samples of all library outputs are returned with unique identifiers corresponding to the output signals of
|
||||
* virtual sensors where the order of the returned outputs may be arbitrary.
|
||||
* - The samples of all input as well as output signals of physical as well as virtual sensors use the same
|
||||
* representation in memory with the following fields:
|
||||
* - Sensor identifier:
|
||||
* - For inputs: required to identify the input signal from a physical sensor
|
||||
* - For output: overwritten by bsec_do_steps() to identify the returned signal from a virtual sensor
|
||||
* - Time stamp of the sample
|
||||
*
|
||||
* Calling bsec_do_steps() requires the samples of the input signals to be provided along with their time stamp when
|
||||
* they are recorded and only when they are acquired. Repetition of samples with the same time stamp are ignored and
|
||||
* result in a warning. Repetition of values of samples which are not acquired anew by a sensor result in deviations
|
||||
* of the computed output signals. Concerning the returned output samples, an important feature is, that a value is
|
||||
* returned for an output only when a new occurrence has been computed. A sample of an output signal is returned only
|
||||
* once.
|
||||
*
|
||||
*
|
||||
* @param[in] inputs Array of input data samples. Each array element represents a sample of a different physical sensor.
|
||||
* @param[in] n_inputs Number of passed input data structs.
|
||||
* @param[out] outputs Array of output data samples. Each array element represents a sample of a different virtual sensor.
|
||||
* @param[in,out] n_outputs [in] Number of allocated output structs, [out] number of outputs returned
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Allocate input and output memory
|
||||
bsec_input_t input[3];
|
||||
uint8_t n_input = 3;
|
||||
bsec_output_t output[2];
|
||||
uint8_t n_output=2;
|
||||
|
||||
bsec_library_return_t status;
|
||||
|
||||
// Populate the input structs, assuming the we have timestamp (ts),
|
||||
// gas sensor resistance (R), temperature (T), and humidity (rH) available
|
||||
// as input variables
|
||||
input[0].sensor_id = BSEC_INPUT_GASRESISTOR;
|
||||
input[0].signal = R;
|
||||
input[0].time_stamp= ts;
|
||||
input[1].sensor_id = BSEC_INPUT_TEMPERATURE;
|
||||
input[1].signal = T;
|
||||
input[1].time_stamp= ts;
|
||||
input[2].sensor_id = BSEC_INPUT_HUMIDITY;
|
||||
input[2].signal = rH;
|
||||
input[2].time_stamp= ts;
|
||||
|
||||
|
||||
// Invoke main processing BSEC function
|
||||
status = bsec_do_steps( input, n_input, output, &n_output );
|
||||
|
||||
// Iterate through the BSEC output data, if the call succeeded
|
||||
if(status == BSEC_OK)
|
||||
{
|
||||
for(int i = 0; i < n_output; i++)
|
||||
{
|
||||
switch(output[i].sensor_id)
|
||||
{
|
||||
case BSEC_OUTPUT_IAQ:
|
||||
// Retrieve the IAQ results from output[i].signal
|
||||
// and do something with the data
|
||||
break;
|
||||
case BSEC_OUTPUT_AMBIENT_TEMPERATURE:
|
||||
// Retrieve the ambient temperature results from output[i].signal
|
||||
// and do something with the data
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_do_steps(const bsec_input_t * const inputs, const uint8_t n_inputs, bsec_output_t * outputs, uint8_t * n_outputs);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Reset a particular virtual sensor output
|
||||
*
|
||||
* This function allows specific virtual sensor outputs to be reset. The meaning of "reset" depends on the specific
|
||||
* output. In case of the IAQ output, reset means zeroing the output to the current ambient conditions.
|
||||
*
|
||||
* @param[in] sensor_id Virtual sensor to be reset
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
bsec_reset_output(BSEC_OUTPUT_IAQ);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_reset_output(uint8_t sensor_id);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Update algorithm configuration parameters
|
||||
*
|
||||
* BSEC uses a default configuration for the modules and common settings. The initial configuration can be customized
|
||||
* by bsec_set_configuration(). This is an optional step.
|
||||
*
|
||||
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose
|
||||
* the serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting
|
||||
* the required size.
|
||||
*
|
||||
* @param[in] serialized_settings Settings serialized to a binary blob
|
||||
* @param[in] n_serialized_settings Size of the settings blob
|
||||
* @param[in,out] work_buffer Work buffer used to parse the blob
|
||||
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Allocate variables
|
||||
uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_work_buffer = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
|
||||
// Here we will load a provided config string into serialized_settings
|
||||
|
||||
// Apply the configuration
|
||||
bsec_set_configuration(serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_settings,
|
||||
const uint32_t n_serialized_settings, uint8_t * work_buffer,
|
||||
const uint32_t n_work_buffer_size);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Restore the internal state of the library
|
||||
*
|
||||
* BSEC uses a default state for all signal processing modules and the BSEC module. To ensure optimal performance,
|
||||
* especially of the gas sensor functionality, it is recommended to retrieve the state using bsec_get_state()
|
||||
* before unloading the library, storing it in some form of non-volatile memory, and setting it using bsec_set_state()
|
||||
* before resuming further operation of the library.
|
||||
*
|
||||
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
|
||||
* serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the
|
||||
* required size.
|
||||
*
|
||||
* @param[in] serialized_state States serialized to a binary blob
|
||||
* @param[in] n_serialized_state Size of the state blob
|
||||
* @param[in,out] work_buffer Work buffer used to parse the blob
|
||||
* @param[in] n_work_buffer_size Length of the work buffer available for parsing the blob
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Allocate variables
|
||||
uint8_t serialized_state[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_serialized_state = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
uint8_t work_buffer_state[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_work_buffer_size = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
|
||||
// Here we will load a state string from a previous use of BSEC
|
||||
|
||||
// Apply the previous state to the current BSEC session
|
||||
bsec_set_state(serialized_state, n_serialized_state, work_buffer_state, n_work_buffer_size);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, const uint32_t n_serialized_state,
|
||||
uint8_t * work_buffer, const uint32_t n_work_buffer_size);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Retrieve the current library configuration
|
||||
*
|
||||
* BSEC allows to retrieve the current configuration using bsec_get_configuration(). Returns a binary blob encoding
|
||||
* the current configuration parameters of the library in a format compatible with bsec_set_configuration().
|
||||
*
|
||||
* @note The function bsec_get_configuration() is required to be used for debugging purposes only.
|
||||
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
|
||||
* serialization and apply it to the library and its modules. Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the
|
||||
* required size.
|
||||
*
|
||||
*
|
||||
* @param[in] config_id Identifier for a specific set of configuration settings to be returned;
|
||||
* shall be zero to retrieve all configuration settings.
|
||||
* @param[out] serialized_settings Buffer to hold the serialized config blob
|
||||
* @param[in] n_serialized_settings_max Maximum available size for the serialized settings
|
||||
* @param[in,out] work_buffer Work buffer used to parse the binary blob
|
||||
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
|
||||
* @param[out] n_serialized_settings Actual size of the returned serialized configuration blob
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Allocate variables
|
||||
uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
uint8_t work_buffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
|
||||
uint32_t n_work_buffer = BSEC_MAX_PROPERTY_BLOB_SIZE;
|
||||
uint32_t n_serialized_settings = 0;
|
||||
|
||||
// Configuration of BSEC algorithm is stored in 'serialized_settings'
|
||||
bsec_get_configuration(0, serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer, &n_serialized_settings);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * serialized_settings, const uint32_t n_serialized_settings_max,
|
||||
uint8_t * work_buffer, const uint32_t n_work_buffer, uint32_t * n_serialized_settings);
|
||||
|
||||
|
||||
/*!
|
||||
*@brief Retrieve the current internal library state
|
||||
*
|
||||
* BSEC allows to retrieve the current states of all signal processing modules and the BSEC module using
|
||||
* bsec_get_state(). This allows a restart of the processing after a reboot of the system by calling bsec_set_state().
|
||||
*
|
||||
* @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the
|
||||
* serialization and apply it to the library and its modules. Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the
|
||||
* required size.
|
||||
*
|
||||
*
|
||||
* @param[in] state_set_id Identifier for a specific set of states to be returned; shall be
|
||||
* zero to retrieve all states.
|
||||
* @param[out] serialized_state Buffer to hold the serialized config blob
|
||||
* @param[in] n_serialized_state_max Maximum available size for the serialized states
|
||||
* @param[in,out] work_buffer Work buffer used to parse the blob
|
||||
* @param[in] n_work_buffer Length of the work buffer available for parsing the blob
|
||||
* @param[out] n_serialized_state Actual size of the returned serialized blob
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*
|
||||
\code{.c}
|
||||
// Example //
|
||||
|
||||
// Allocate variables
|
||||
uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
uint32_t n_serialized_state_max = BSEC_MAX_STATE_BLOB_SIZE;
|
||||
uint32_t n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
|
||||
uint8_t work_buffer_state[BSEC_MAX_STATE_BLOB_SIZE];
|
||||
uint32_t n_work_buffer_size = BSEC_MAX_STATE_BLOB_SIZE;
|
||||
|
||||
// Algorithm state is stored in 'serialized_state'
|
||||
bsec_get_state(0, serialized_state, n_serialized_state_max, work_buffer_state, n_work_buffer_size, &n_serialized_state);
|
||||
|
||||
\endcode
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_get_state(const uint8_t state_set_id, uint8_t * serialized_state,
|
||||
const uint32_t n_serialized_state_max, uint8_t * work_buffer, const uint32_t n_work_buffer,
|
||||
uint32_t * n_serialized_state);
|
||||
|
||||
/*!
|
||||
* @brief Retrieve BMExxx sensor instructions
|
||||
*
|
||||
* The bsec_sensor_control() interface is a key feature of BSEC, as it allows an easy way for the signal processing
|
||||
* library to control the operation of the BME sensor. This is important since gas sensor behaviour is mainly
|
||||
* determined by how the integrated heater is configured. To ensure an easy integration of BSEC into any system,
|
||||
* bsec_sensor_control() will provide the caller with information about the current sensor configuration that is
|
||||
* necessary to fulfill the input requirements derived from the current outputs requested via
|
||||
* bsec_update_subscription().
|
||||
*
|
||||
* In practice the use of this function shall be as follows:
|
||||
* - Call bsec_sensor_control() which returns a bsec_bme_settings_t struct.
|
||||
* - Based on the information contained in this struct, the sensor is configured and a forced-mode measurement is
|
||||
* triggered if requested by bsec_sensor_control().
|
||||
* - Once this forced-mode measurement is complete, the signals specified in this struct shall be passed to
|
||||
* bsec_do_steps() to perform the signal processing.
|
||||
* - After processing, the process should sleep until the bsec_bme_settings_t::next_call timestamp is reached.
|
||||
*
|
||||
*
|
||||
* @param [in] time_stamp Current timestamp in [ns]
|
||||
* @param[out] sensor_settings Settings to be passed to API to operate sensor at this time instance
|
||||
*
|
||||
* @return Zero when successful, otherwise an error code
|
||||
*/
|
||||
|
||||
bsec_library_return_t bsec_sensor_control(const int64_t time_stamp, bsec_bme_settings_t *sensor_settings);
|
||||
|
||||
/*@}*/ //BSEC Interface
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BSEC_INTERFACE_H__ */
|
@ -1,502 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
@ -1,124 +0,0 @@
|
||||
# EspSoftwareSerial
|
||||
|
||||
## Implementation of the Arduino software serial library for the ESP8266 / ESP32
|
||||
|
||||
This fork implements interrupt service routine best practice.
|
||||
In the receive interrupt, instead of blocking for whole bytes
|
||||
at a time - voiding any near-realtime behavior of the CPU - only level
|
||||
change and timestamp are recorded. The more time consuming phase
|
||||
detection and byte assembly are done in the main code.
|
||||
|
||||
Except at high bitrates, depending on other ongoing activity,
|
||||
interrupts in particular, this software serial adapter
|
||||
supports full duplex receive and send. At high bitrates (115200bps)
|
||||
send bit timing can be improved at the expense of blocking concurrent
|
||||
full duplex receives, with the ``SoftwareSerial::enableIntTx(false)`` function call.
|
||||
|
||||
The same functionality is given as the corresponding AVR library but
|
||||
several instances can be active at the same time. Speed up to 115200 baud
|
||||
is supported. Besides a constructor compatible to the AVR SoftwareSerial class,
|
||||
and updated constructor that takes no arguments exists, instead the ``begin()``
|
||||
function can handle the pin assignments and logic inversion.
|
||||
It also has optional input buffer capacity arguments for byte buffer and ISR bit buffer.
|
||||
This way, it is a better drop-in replacement for the hardware serial APIs on the ESP MCUs.
|
||||
|
||||
Please note that due to the fact that the ESPs always have other activities
|
||||
ongoing, there will be some inexactness in interrupt timings. This may
|
||||
lead to inevitable, but few, bit errors when having heavy data traffic
|
||||
at high baud rates.
|
||||
|
||||
## Resource optimization
|
||||
|
||||
The memory footprint can be optimized to just fit the amount of expected
|
||||
incoming asynchronous data.
|
||||
For this, the ``SoftwareSerial`` constructor provides two arguments. First, the
|
||||
octet buffer capacity for assembled received octets can be set. Read calls are
|
||||
satisfied from this buffer, freeing it in return.
|
||||
Second, the signal edge detection buffer of 32bit fields can be resized.
|
||||
One octet may require up to to 10 fields, but fewer may be needed,
|
||||
depending on the bit pattern. Any read or write calls check this buffer
|
||||
to assemble received octets, thus promoting completed octets to the octet
|
||||
buffer, freeing fields in the edge detection buffer.
|
||||
|
||||
Look at the swsertest.ino example. There, on reset, ASCII characters ' ' to 'z'
|
||||
are sent. This happens not as a block write, but in a single write call per
|
||||
character. As the example uses a local loopback wire, every outgoing bit is
|
||||
immediately received back. Therefore, any single write call causes up to
|
||||
10 fields - depending on the exact bit pattern - to be occupied in the signal
|
||||
edge detection buffer. In turn, as explained before, each single write call
|
||||
also causes received bit assembly to be performed, promoting these bits from
|
||||
the signal edge detection buffer to the octet buffer as soon as possible.
|
||||
Explaining by way of contrast, if during a a single write call, perhaps because
|
||||
of using block writing, more than a single octet is received, there will be a
|
||||
need for more than 10 fields in the signal edge detection buffer.
|
||||
The necessary capacity of the octet buffer only depends on the amount of incoming
|
||||
data until the next read call.
|
||||
|
||||
For the swsertest.ino example, this results in the following optimized
|
||||
constructor arguments to spend only the minimum RAM on buffers required:
|
||||
|
||||
The octet buffer capacity (``bufCapacity``) is 93 (91 characters net plus two tolerance).
|
||||
The signal edge detection buffer capacity (``isrBufCapacity``) is 10, as each octet has
|
||||
10 bits on the wire, which are immediately received during the write, and each
|
||||
write call causes the signal edge detection to promote the previously sent and
|
||||
received bits to the octet buffer.
|
||||
|
||||
In a more generalized scenario, calculate the bits (use message size in octets
|
||||
times 10) that may be asynchronously received to determine the value for
|
||||
``isrBufCapacity`` in the constructor. Also use the number of received octets
|
||||
that must be buffered for reading as the value of ``bufCapacity``.
|
||||
The more frequently your code calls write or read functions, the greater the
|
||||
chances are that you can reduce the ``isrBufCapacity`` footprint without losing data,
|
||||
and each time you call read to fetch from the octet buffer, you reduce the
|
||||
need for space there.
|
||||
|
||||
## SoftwareSerialConfig and parity
|
||||
The configuration of the data stream is done via a ``SoftwareSerialConfig``
|
||||
argument to ``begin()``. Word lengths can be set to between 5 and 8 bits, parity
|
||||
can be N(one), O(dd) or E(ven) and 1 or 2 stop bits can be used. The default is
|
||||
``SWSERIAL_8N1`` using 8 bits, no parity and 1 stop bit but any combination can
|
||||
be used, e.g. ``SWSERIAL_7E2``. If using EVEN or ODD parity, any parity errors
|
||||
can be detected with the ``peekParityError()`` function. Note that parity
|
||||
checking must be done before ``read()``, as the parity information is removed
|
||||
from the buffer when reading the corresponding byte.
|
||||
|
||||
To allow flexible 9-bit and data/addressing protocols, the additional parity
|
||||
modes MARK and SPACE are also available. Furthermore, the parity mode can be
|
||||
individually set in each call to ``write()``.
|
||||
|
||||
This allows a simple implementation of protocols where the parity bit is used to
|
||||
distinguish between data and addresses/commands ("9-bit" protocols). First set
|
||||
up SoftwareSerial with parity mode SPACE, e.g. ``SWSERIAL_8S1``. This will add a
|
||||
parity bit to every byte sent, setting it to logical zero (SPACE parity).
|
||||
|
||||
To detect incoming bytes with the parity bit set (MARK parity), use the
|
||||
``peekParityError()`` function. To send a byte with the parity bit set, just add
|
||||
``MARK`` as the second argument when writing, e.g. ``write(ch, MARK)``.
|
||||
|
||||
## Using and updating EspSoftwareSerial in the esp8266com/esp8266 Arduino build environment
|
||||
|
||||
EspSoftwareSerial is both part of the BSP download for ESP8266 in Arduino,
|
||||
and it is set up as a Git submodule in the esp8266 source tree,
|
||||
specifically in ``.../esp8266/libraries/SoftwareSerial`` when using a Github
|
||||
repository clone in your Arduino sketchbook hardware directory.
|
||||
This supersedes any version of EspSoftwareSerial installed for instance via
|
||||
the Arduino library manager, it is not required to install EspSoftwareSerial
|
||||
for the ESP8266 separately at all, but doing so has ill effect.
|
||||
|
||||
The responsible maintainer of the esp8266 repository has kindly shared the
|
||||
following command line instructions to use, if one wishes to manually
|
||||
update EspSoftwareSerial to a newer release than pulled in via the ESP8266 Arduino BSP:
|
||||
|
||||
To update esp8266/arduino SoftwareSerial submodule to lastest master:
|
||||
|
||||
Clean it (optional):
|
||||
```shell
|
||||
$ rm -rf libraries/SoftwareSerial
|
||||
$ git submodule update --init
|
||||
```
|
||||
Now update it:
|
||||
```shell
|
||||
$ cd libraries/SoftwareSerial
|
||||
$ git checkout master
|
||||
$ git pull
|
||||
```
|
@ -1,263 +0,0 @@
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
// On ESP8266:
|
||||
// Local SoftwareSerial loopback, connect D5 (rx) and D6 (tx).
|
||||
// For local hardware loopback, connect D5 to D8 (tx), D6 to D7 (rx).
|
||||
// For hardware send/sink, connect D7 (rx) and D8 (tx).
|
||||
// Hint: The logger is run at 9600bps such that enableIntTx(true) can remain unchanged. Blocking
|
||||
// interrupts severely impacts the ability of the SoftwareSerial devices to operate concurrently
|
||||
// and/or in duplex mode.
|
||||
// Operating in software serial full duplex mode, runs at 19200bps and few errors (~2.5%).
|
||||
// Operating in software serial half duplex mode (both loopback and repeater),
|
||||
// runs at 57600bps with nearly no errors.
|
||||
// Operating loopback in full duplex, and repeater in half duplex, runs at 38400bps with nearly no errors.
|
||||
// On ESP32:
|
||||
// For SoftwareSerial or hardware send/sink, connect D5 (rx) and D6 (tx).
|
||||
// Hardware Serial2 defaults to D4 (rx), D3 (tx).
|
||||
// For local hardware loopback, connect D5 (rx) to D3 (tx), D6 (tx) to D4 (rx).
|
||||
|
||||
#if defined(ESP8266) && !defined(D5)
|
||||
#define D5 (14)
|
||||
#define D6 (12)
|
||||
#define D7 (13)
|
||||
#define D8 (15)
|
||||
#define TX (1)
|
||||
#endif
|
||||
|
||||
// Pick only one of HWLOOPBACK, HWSOURCESWSINK, or HWSOURCESINK
|
||||
//#define HWLOOPBACK 1
|
||||
//#define HWSOURCESWSINK 1
|
||||
//#define HWSOURCESINK 1
|
||||
#define HALFDUPLEX 1
|
||||
|
||||
#ifdef ESP32
|
||||
constexpr int IUTBITRATE = 19200;
|
||||
#else
|
||||
constexpr int IUTBITRATE = 19200;
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
|
||||
constexpr SerialConfig hwSerialConfig = SERIAL_8E1;
|
||||
#elif defined(ESP32)
|
||||
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
|
||||
constexpr uint32_t hwSerialConfig = SERIAL_8E1;
|
||||
#else
|
||||
constexpr unsigned swSerialConfig = 3;
|
||||
#endif
|
||||
constexpr bool invert = false;
|
||||
|
||||
constexpr int BLOCKSIZE = 16; // use fractions of 256
|
||||
|
||||
unsigned long start;
|
||||
String effTxTxt("eff. tx: ");
|
||||
String effRxTxt("eff. rx: ");
|
||||
int txCount;
|
||||
int rxCount;
|
||||
int expected;
|
||||
int rxErrors;
|
||||
int rxParityErrors;
|
||||
constexpr int ReportInterval = IUTBITRATE / 8;
|
||||
|
||||
#if defined(ESP8266)
|
||||
#if defined(HWLOOPBACK) || defined(HWSOURCESWSINK)
|
||||
HardwareSerial& hwSerial(Serial);
|
||||
SoftwareSerial serialIUT;
|
||||
SoftwareSerial logger;
|
||||
#elif defined(HWSOURCESINK)
|
||||
HardwareSerial& serialIUT(Serial);
|
||||
SoftwareSerial logger;
|
||||
#else
|
||||
SoftwareSerial serialIUT;
|
||||
HardwareSerial& logger(Serial);
|
||||
#endif
|
||||
#elif defined(ESP32)
|
||||
#if defined(HWLOOPBACK) || defined (HWSOURCESWSINK)
|
||||
HardwareSerial& hwSerial(Serial2);
|
||||
SoftwareSerial serialIUT;
|
||||
#elif defined(HWSOURCESINK)
|
||||
HardwareSerial& serialIUT(Serial2);
|
||||
#else
|
||||
SoftwareSerial serialIUT;
|
||||
#endif
|
||||
HardwareSerial& logger(Serial);
|
||||
#else
|
||||
SoftwareSerial serialIUT(14, 12);
|
||||
HardwareSerial& logger(Serial);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
#if defined(ESP8266)
|
||||
#if defined(HWLOOPBACK) || defined(HWSOURCESINK) || defined(HWSOURCESWSINK)
|
||||
Serial.begin(IUTBITRATE, hwSerialConfig, SERIAL_FULL, 1, invert);
|
||||
Serial.swap();
|
||||
Serial.setRxBufferSize(2 * BLOCKSIZE);
|
||||
logger.begin(9600, SWSERIAL_8N1, -1, TX);
|
||||
#else
|
||||
logger.begin(9600);
|
||||
#endif
|
||||
#if !defined(HWSOURCESINK)
|
||||
serialIUT.begin(IUTBITRATE, swSerialConfig, D5, D6, invert, 2 * BLOCKSIZE);
|
||||
#ifdef HALFDUPLEX
|
||||
serialIUT.enableIntTx(false);
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(ESP32)
|
||||
#if defined(HWLOOPBACK) || defined(HWSOURCESWSINK)
|
||||
Serial2.begin(IUTBITRATE, hwSerialConfig, D4, D3, invert);
|
||||
Serial2.setRxBufferSize(2 * BLOCKSIZE);
|
||||
#elif defined(HWSOURCESINK)
|
||||
serialIUT.begin(IUTBITRATE, hwSerialConfig, D5, D6, invert);
|
||||
serialIUT.setRxBufferSize(2 * BLOCKSIZE);
|
||||
#endif
|
||||
#if !defined(HWSOURCESINK)
|
||||
serialIUT.begin(IUTBITRATE, swSerialConfig, D5, D6, invert, 2 * BLOCKSIZE);
|
||||
#ifdef HALFDUPLEX
|
||||
serialIUT.enableIntTx(false);
|
||||
#endif
|
||||
#endif
|
||||
logger.begin(9600);
|
||||
#else
|
||||
#if !defined(HWSOURCESINK)
|
||||
serialIUT.begin(IUTBITRATE);
|
||||
#endif
|
||||
logger.begin(9600);
|
||||
#endif
|
||||
|
||||
logger.println("Loopback example for EspSoftwareSerial");
|
||||
|
||||
start = micros();
|
||||
txCount = 0;
|
||||
rxCount = 0;
|
||||
rxErrors = 0;
|
||||
rxParityErrors = 0;
|
||||
expected = -1;
|
||||
}
|
||||
|
||||
unsigned char c = 0;
|
||||
|
||||
void loop() {
|
||||
#ifdef HALFDUPLEX
|
||||
char block[BLOCKSIZE];
|
||||
#endif
|
||||
char inBuf[BLOCKSIZE];
|
||||
for (int i = 0; i < BLOCKSIZE; ++i) {
|
||||
#ifndef HALFDUPLEX
|
||||
#ifdef HWSOURCESWSINK
|
||||
hwSerial.write(c);
|
||||
#else
|
||||
serialIUT.write(c);
|
||||
#endif
|
||||
#ifdef HWLOOPBACK
|
||||
int avail = hwSerial.available();
|
||||
while ((0 == (i % 8)) && avail > 0) {
|
||||
int inCnt = hwSerial.read(inBuf, min(avail, min(BLOCKSIZE, hwSerial.availableForWrite())));
|
||||
hwSerial.write(inBuf, inCnt);
|
||||
avail -= inCnt;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
block[i] = c;
|
||||
#endif
|
||||
c = (c + 1) % 256;
|
||||
++txCount;
|
||||
}
|
||||
#ifdef HALFDUPLEX
|
||||
#ifdef HWSOURCESWSINK
|
||||
hwSerial.write(block, BLOCKSIZE);
|
||||
#else
|
||||
serialIUT.write(block, BLOCKSIZE);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HWSOURCESINK
|
||||
#if defined(ESP8266)
|
||||
if (serialIUT.hasOverrun()) { logger.println("serialIUT.overrun"); }
|
||||
#endif
|
||||
#else
|
||||
if (serialIUT.overflow()) { logger.println("serialIUT.overflow"); }
|
||||
#endif
|
||||
|
||||
int inCnt;
|
||||
uint32_t deadlineStart;
|
||||
|
||||
#ifdef HWLOOPBACK
|
||||
// starting deadline for the first bytes to become readable
|
||||
deadlineStart = ESP.getCycleCount();
|
||||
inCnt = 0;
|
||||
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 24 * ESP.getCpuFreqMHz()) {
|
||||
int avail = hwSerial.available();
|
||||
inCnt += hwSerial.read(&inBuf[inCnt], min(avail, min(BLOCKSIZE - inCnt, hwSerial.availableForWrite())));
|
||||
if (inCnt >= BLOCKSIZE) { break; }
|
||||
// wait for more outstanding bytes to trickle in
|
||||
if (avail) deadlineStart = ESP.getCycleCount();
|
||||
}
|
||||
hwSerial.write(inBuf, inCnt);
|
||||
#endif
|
||||
|
||||
// starting deadline for the first bytes to come in
|
||||
deadlineStart = ESP.getCycleCount();
|
||||
inCnt = 0;
|
||||
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 8 * ESP.getCpuFreqMHz()) {
|
||||
int avail;
|
||||
if (0 != (swSerialConfig & 070))
|
||||
avail = serialIUT.available();
|
||||
else
|
||||
avail = serialIUT.read(inBuf, BLOCKSIZE);
|
||||
for (int i = 0; i < avail; ++i)
|
||||
{
|
||||
unsigned char r;
|
||||
if (0 != (swSerialConfig & 070))
|
||||
r = serialIUT.read();
|
||||
else
|
||||
r = inBuf[i];
|
||||
if (expected == -1) { expected = r; }
|
||||
else {
|
||||
expected = (expected + 1) % (1UL << (5 + swSerialConfig % 4));
|
||||
}
|
||||
if (r != expected) {
|
||||
++rxErrors;
|
||||
expected = -1;
|
||||
}
|
||||
#ifndef HWSOURCESINK
|
||||
if (serialIUT.readParity() != (static_cast<bool>(swSerialConfig & 010) ? serialIUT.parityOdd(r) : serialIUT.parityEven(r)))
|
||||
{
|
||||
++rxParityErrors;
|
||||
}
|
||||
#endif
|
||||
++rxCount;
|
||||
++inCnt;
|
||||
}
|
||||
|
||||
if (inCnt >= BLOCKSIZE) { break; }
|
||||
// wait for more outstanding bytes to trickle in
|
||||
if (avail) deadlineStart = ESP.getCycleCount();
|
||||
}
|
||||
|
||||
const uint32_t interval = micros() - start;
|
||||
if (txCount >= ReportInterval && interval) {
|
||||
uint8_t wordBits = (5 + swSerialConfig % 4) + static_cast<bool>(swSerialConfig & 070) + 1 + ((swSerialConfig & 0300) ? 1 : 0);
|
||||
logger.println(String("tx/rx: ") + txCount + "/" + rxCount);
|
||||
const long txCps = txCount * (1000000.0 / interval);
|
||||
const long rxCps = rxCount * (1000000.0 / interval);
|
||||
logger.print(effTxTxt + wordBits * txCps + "bps, "
|
||||
+ effRxTxt + wordBits * rxCps + "bps, "
|
||||
+ rxErrors + " errors (" + 100.0 * rxErrors / (!rxErrors ? 1 : rxCount) + "%)");
|
||||
if (0 != (swSerialConfig & 070))
|
||||
{
|
||||
logger.print(" ("); logger.print(rxParityErrors); logger.println(" parity errors)");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.println();
|
||||
}
|
||||
txCount = 0;
|
||||
rxCount = 0;
|
||||
rxErrors = 0;
|
||||
rxParityErrors = 0;
|
||||
expected = -1;
|
||||
// resync
|
||||
delay(1000UL * 12 * BLOCKSIZE / IUTBITRATE * 16);
|
||||
serialIUT.flush();
|
||||
start = micros();
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
SoftwareSerial swSer1;
|
||||
SoftwareSerial swSer2;
|
||||
|
||||
void setup() {
|
||||
delay(2000);
|
||||
Serial.begin(115200);
|
||||
Serial.println("\nOne Wire Half Duplex Serial Tester");
|
||||
swSer1.begin(115200, SWSERIAL_8N1, 12, 12, false, 256);
|
||||
swSer1.enableIntTx(true);
|
||||
swSer2.begin(115200, SWSERIAL_8N1, 14, 14, false, 256);
|
||||
swSer2.enableIntTx(true);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("\n\nTesting on swSer1");
|
||||
Serial.print("Enter something to send using swSer1.");
|
||||
checkSwSerial(&swSer1);
|
||||
|
||||
Serial.println("\n\nTesting on swSer2");
|
||||
Serial.print("Enter something to send using swSer2.");
|
||||
checkSwSerial(&swSer2);
|
||||
|
||||
}
|
||||
|
||||
void checkSwSerial(SoftwareSerial* ss) {
|
||||
byte ch;
|
||||
while (!Serial.available());
|
||||
ss->enableTx(true);
|
||||
while (Serial.available()) {
|
||||
ch = Serial.read();
|
||||
ss->write(ch);
|
||||
}
|
||||
ss->enableTx(false);
|
||||
// wait 1 second for the reply from SOftwareSerial if any
|
||||
delay(1000);
|
||||
if (ss->available()) {
|
||||
Serial.print("\nResult:");
|
||||
while (ss->available()) {
|
||||
ch = (byte)ss->read();
|
||||
Serial.print(ch < 0x01 ? " 0" : " ");
|
||||
Serial.print(ch, HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
// On ESP8266:
|
||||
// SoftwareSerial loopback for remote source (loopback.ino), or hardware loopback.
|
||||
// Connect source D5 (rx) to local D8 (tx), source D6 (tx) to local D7 (rx).
|
||||
// Hint: The logger is run at 9600bps such that enableIntTx(true) can remain unchanged. Blocking
|
||||
// interrupts severely impacts the ability of the SoftwareSerial devices to operate concurrently
|
||||
// and/or in duplex mode.
|
||||
// On ESP32:
|
||||
// For software or hardware loopback, connect source rx to local D8 (tx), source tx to local D7 (rx).
|
||||
|
||||
#if defined(ESP8266) && !defined(D5)
|
||||
#define D5 (14)
|
||||
#define D6 (12)
|
||||
#define D7 (13)
|
||||
#define D8 (15)
|
||||
#define TX (1)
|
||||
#endif
|
||||
|
||||
#define HWLOOPBACK 1
|
||||
#define HALFDUPLEX 1
|
||||
|
||||
#ifdef ESP32
|
||||
constexpr int IUTBITRATE = 19200;
|
||||
#else
|
||||
constexpr int IUTBITRATE = 19200;
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
|
||||
constexpr SerialConfig hwSerialConfig = SERIAL_8E1;
|
||||
#elif defined(ESP32)
|
||||
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
|
||||
constexpr uint32_t hwSerialConfig = SERIAL_8E1;
|
||||
#else
|
||||
constexpr unsigned swSerialConfig = 3;
|
||||
#endif
|
||||
constexpr bool invert = false;
|
||||
|
||||
constexpr int BLOCKSIZE = 16; // use fractions of 256
|
||||
|
||||
unsigned long start;
|
||||
String bitRateTxt("Effective data rate: ");
|
||||
int rxCount;
|
||||
int seqErrors;
|
||||
int parityErrors;
|
||||
int expected;
|
||||
constexpr int ReportInterval = IUTBITRATE / 8;
|
||||
|
||||
#if defined(ESP8266)
|
||||
#if defined(HWLOOPBACK)
|
||||
HardwareSerial& repeater(Serial);
|
||||
SoftwareSerial logger;
|
||||
#else
|
||||
SoftwareSerial repeater;
|
||||
HardwareSerial& logger(Serial);
|
||||
#endif
|
||||
#elif defined(ESP32)
|
||||
#if defined(HWLOOPBACK)
|
||||
HardwareSerial& repeater(Serial2);
|
||||
#else
|
||||
SoftwareSerial repeater;
|
||||
#endif
|
||||
HardwareSerial& logger(Serial);
|
||||
#else
|
||||
SoftwareSerial repeater(14, 12);
|
||||
HardwareSerial& logger(Serial);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
#if defined(ESP8266)
|
||||
#if defined(HWLOOPBACK)
|
||||
repeater.begin(IUTBITRATE, hwSerialConfig, SERIAL_FULL, 1, invert);
|
||||
repeater.swap();
|
||||
repeater.setRxBufferSize(2 * BLOCKSIZE);
|
||||
logger.begin(9600, SWSERIAL_8N1, -1, TX);
|
||||
#else
|
||||
repeater.begin(IUTBITRATE, swSerialConfig, D7, D8, invert, 4 * BLOCKSIZE);
|
||||
#ifdef HALFDUPLEX
|
||||
repeater.enableIntTx(false);
|
||||
#endif
|
||||
logger.begin(9600);
|
||||
#endif
|
||||
#elif defined(ESP32)
|
||||
#if defined(HWLOOPBACK)
|
||||
repeater.begin(IUTBITRATE, hwSerialConfig, D7, D8, invert);
|
||||
repeater.setRxBufferSize(2 * BLOCKSIZE);
|
||||
#else
|
||||
repeater.begin(IUTBITRATE, swSerialConfig, D7, D8, invert, 4 * BLOCKSIZE);
|
||||
#ifdef HALFDUPLEX
|
||||
repeater.enableIntTx(false);
|
||||
#endif
|
||||
#endif
|
||||
logger.begin(9600);
|
||||
#else
|
||||
repeater.begin(IUTBITRATE);
|
||||
logger.begin(9600);
|
||||
#endif
|
||||
|
||||
logger.println("Repeater example for EspSoftwareSerial");
|
||||
start = micros();
|
||||
rxCount = 0;
|
||||
seqErrors = 0;
|
||||
parityErrors = 0;
|
||||
expected = -1;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
#ifdef HWLOOPBACK
|
||||
#if defined(ESP8266)
|
||||
if (repeater.hasOverrun()) { logger.println("repeater.overrun"); }
|
||||
#endif
|
||||
#else
|
||||
if (repeater.overflow()) { logger.println("repeater.overflow"); }
|
||||
#endif
|
||||
|
||||
#ifdef HALFDUPLEX
|
||||
char block[BLOCKSIZE];
|
||||
#endif
|
||||
// starting deadline for the first bytes to come in
|
||||
uint32_t deadlineStart = ESP.getCycleCount();
|
||||
int inCnt = 0;
|
||||
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 24 * ESP.getCpuFreqMHz()) {
|
||||
int avail = repeater.available();
|
||||
for (int i = 0; i < avail; ++i)
|
||||
{
|
||||
int r = repeater.read();
|
||||
if (r == -1) { logger.println("read() == -1"); }
|
||||
if (expected == -1) { expected = r; }
|
||||
else {
|
||||
expected = (expected + 1) % (1UL << (5 + swSerialConfig % 4));
|
||||
}
|
||||
if (r != expected) {
|
||||
++seqErrors;
|
||||
expected = -1;
|
||||
}
|
||||
#ifndef HWLOOPBACK
|
||||
if (repeater.readParity() != (static_cast<bool>(swSerialConfig & 010) ? repeater.parityOdd(r) : repeater.parityEven(r)))
|
||||
{
|
||||
++parityErrors;
|
||||
}
|
||||
#endif
|
||||
++rxCount;
|
||||
#ifdef HALFDUPLEX
|
||||
block[inCnt] = r;
|
||||
#else
|
||||
repeater.write(r);
|
||||
#endif
|
||||
if (++inCnt >= BLOCKSIZE) { break; }
|
||||
}
|
||||
if (inCnt >= BLOCKSIZE) { break; }
|
||||
// wait for more outstanding bytes to trickle in
|
||||
if (avail) deadlineStart = ESP.getCycleCount();
|
||||
}
|
||||
|
||||
#ifdef HALFDUPLEX
|
||||
repeater.write(block, inCnt);
|
||||
#endif
|
||||
|
||||
if (rxCount >= ReportInterval) {
|
||||
auto end = micros();
|
||||
unsigned long interval = end - start;
|
||||
long cps = rxCount * (1000000.0 / interval);
|
||||
long seqErrorsps = seqErrors * (1000000.0 / interval);
|
||||
logger.print(bitRateTxt + 10 * cps + "bps, "
|
||||
+ seqErrorsps + "cps seq. errors (" + 100.0 * seqErrors / rxCount + "%)");
|
||||
#ifndef HWLOOPBACK
|
||||
if (0 != (swSerialConfig & 070))
|
||||
{
|
||||
logger.print(" ("); logger.print(parityErrors); logger.print(" parity errors)");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
logger.println();
|
||||
}
|
||||
start = end;
|
||||
rxCount = 0;
|
||||
seqErrors = 0;
|
||||
parityErrors = 0;
|
||||
expected = -1;
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
SoftwareSerial swSer;
|
||||
|
||||
byte buf[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED };
|
||||
byte cmd[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED };
|
||||
byte ver[10] = { 0xFC, 0xCF,0x00,0xAA,0x41, 0x16, 0x51, 0x01, 0x00, 0xED };
|
||||
|
||||
|
||||
void setup() {
|
||||
delay(2000);
|
||||
Serial.begin(115200);
|
||||
Serial.println("\nAlpha 1S Servo Tester");
|
||||
swSer.begin(115200, SWSERIAL_8N1, 12, 12, false, 256);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (int i = 1; i <= 32; i++) {
|
||||
GetVersion(i);
|
||||
delay(100);
|
||||
}
|
||||
SetLED(1, 0);
|
||||
GoPos(1, 0, 50);
|
||||
delay(1000);
|
||||
GoPos(1, 90, 50);
|
||||
delay(1000);
|
||||
GoPos(1, 100, 50);
|
||||
delay(1000);
|
||||
SetLED(1, 1);
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void GetVersion(byte id) {
|
||||
memcpy(buf, cmd, 10);
|
||||
buf[0] = 0xFC;
|
||||
buf[1] = 0xCF;
|
||||
buf[2] = id;
|
||||
buf[3] = 0x01;
|
||||
SendCommand();
|
||||
}
|
||||
|
||||
|
||||
void GoPos(byte id, byte Pos, byte Time) {
|
||||
memcpy(buf, cmd, 10);
|
||||
buf[2] = id;
|
||||
buf[3] = 0x01;
|
||||
buf[4] = Pos;
|
||||
buf[5] = Time;
|
||||
buf[6] = 0x00;
|
||||
buf[7] = Time;
|
||||
SendCommand();
|
||||
}
|
||||
|
||||
void GetPos(byte id) {
|
||||
memcpy(buf, cmd, 10);
|
||||
buf[2] = id;
|
||||
buf[3] = 0x02;
|
||||
SendCommand();
|
||||
}
|
||||
|
||||
|
||||
void SetLED(byte id, byte mode) {
|
||||
memcpy(buf, cmd, 10);
|
||||
buf[2] = id;
|
||||
buf[3] = 0x04;
|
||||
buf[4] = mode;
|
||||
SendCommand();
|
||||
}
|
||||
|
||||
void SendCommand() {
|
||||
SendCommand(true);
|
||||
}
|
||||
|
||||
void SendCommand(bool checkResult) {
|
||||
byte sum = 0;
|
||||
for (int i = 2; i < 8; i++) {
|
||||
sum += buf[i];
|
||||
}
|
||||
buf[8] = sum;
|
||||
ShowCommand();
|
||||
swSer.flush();
|
||||
swSer.enableTx(true);
|
||||
swSer.write(buf, 10);
|
||||
swSer.enableTx(false);
|
||||
if (checkResult) checkReturn();
|
||||
}
|
||||
|
||||
void ShowCommand() {
|
||||
Serial.print(millis());
|
||||
Serial.print(" OUT>>");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Serial.print((buf[i] < 0x10 ? " 0" : " "));
|
||||
Serial.print(buf[i], HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void checkReturn() {
|
||||
unsigned long startMs = millis();
|
||||
while (((millis() - startMs) < 500) && (!swSer.available()));
|
||||
if (swSer.available()) {
|
||||
Serial.print(millis());
|
||||
Serial.print(" IN>>>");
|
||||
while (swSer.available()) {
|
||||
byte ch = (byte)swSer.read();
|
||||
Serial.print((ch < 0x10 ? " 0" : " "));
|
||||
Serial.print(ch, HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// On ESP8266:
|
||||
// At 80MHz runs up 57600ps, and at 160MHz CPU frequency up to 115200bps with only negligible errors.
|
||||
// Connect pin 12 to 14.
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#if defined(ESP8266) && !defined(D5)
|
||||
#define D5 (14)
|
||||
#define D6 (12)
|
||||
#define D7 (13)
|
||||
#define D8 (15)
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#define BAUD_RATE 57600
|
||||
#else
|
||||
#define BAUD_RATE 57600
|
||||
#endif
|
||||
|
||||
// Reminder: the buffer size optimizations here, in particular the isrBufSize that only accommodates
|
||||
// a single 8N1 word, are on the basis that any char written to the loopback SoftwareSerial adapter gets read
|
||||
// before another write is performed. Block writes with a size greater than 1 would usually fail.
|
||||
SoftwareSerial swSer;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
swSer.begin(BAUD_RATE, SWSERIAL_8N1, D5, D6, false, 95, 11);
|
||||
|
||||
Serial.println("\nSoftware serial test started");
|
||||
|
||||
for (char ch = ' '; ch <= 'z'; ch++) {
|
||||
swSer.write(ch);
|
||||
}
|
||||
swSer.println("");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (swSer.available() > 0) {
|
||||
Serial.write(swSer.read());
|
||||
yield();
|
||||
}
|
||||
while (Serial.available() > 0) {
|
||||
swSer.write(Serial.read());
|
||||
yield();
|
||||
}
|
||||
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map for SoftwareSerial
|
||||
# (esp8266)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SoftwareSerial KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
baudRate KEYWORD2
|
||||
setTransmitEnablePin KEYWORD2
|
||||
enableIntTx KEYWORD2
|
||||
overflow KEYWORD2
|
||||
available KEYWORD2
|
||||
peek KEYWORD2
|
||||
read KEYWORD2
|
||||
flush KEYWORD2
|
||||
write KEYWORD2
|
||||
enableRx KEYWORD2
|
||||
enableTx KEYWORD2
|
||||
listen KEYWORD2
|
||||
end KEYWORD2
|
||||
isListening KEYWORD2
|
||||
stopListening KEYWORD2
|
||||
onReceive KEYWORD2
|
||||
perform_work KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
SW_SERIAL_UNUSED_PIN LITERAL1
|
||||
SWSERIAL_5N1 LITERAL1
|
||||
SWSERIAL_6N1 LITERAL1
|
||||
SWSERIAL_7N1 LITERAL1
|
||||
SWSERIAL_8N1 LITERAL1
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "EspSoftwareSerial",
|
||||
"version": "6.6.1",
|
||||
"keywords": [
|
||||
"serial", "io", "softwareserial"
|
||||
],
|
||||
"description": "Implementation of the Arduino software serial for ESP8266/ESP32.",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/plerup/espsoftwareserial"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
name=EspSoftwareSerial
|
||||
version=6.6.1
|
||||
author=Peter Lerup, Dirk Kaar
|
||||
maintainer=Peter Lerup <peter@lerup.com>
|
||||
sentence=Implementation of the Arduino software serial for ESP8266/ESP32.
|
||||
paragraph=
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/plerup/espsoftwareserial/
|
||||
architectures=esp8266,esp32
|
@ -1,542 +0,0 @@
|
||||
/*
|
||||
|
||||
SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266/ESP32.
|
||||
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
|
||||
Copyright (c) 2018-2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "SoftwareSerial.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef ESP32
|
||||
#define xt_rsil(a) (a)
|
||||
#define xt_wsr_ps(a)
|
||||
#endif
|
||||
|
||||
constexpr uint8_t BYTE_ALL_BITS_SET = ~static_cast<uint8_t>(0);
|
||||
|
||||
SoftwareSerial::SoftwareSerial() {
|
||||
m_isrOverflow = false;
|
||||
}
|
||||
|
||||
SoftwareSerial::SoftwareSerial(int8_t rxPin, int8_t txPin, bool invert)
|
||||
{
|
||||
m_isrOverflow = false;
|
||||
m_rxPin = rxPin;
|
||||
m_txPin = txPin;
|
||||
m_invert = invert;
|
||||
}
|
||||
|
||||
SoftwareSerial::~SoftwareSerial() {
|
||||
end();
|
||||
}
|
||||
|
||||
bool SoftwareSerial::isValidGPIOpin(int8_t pin) {
|
||||
#if defined(ESP8266)
|
||||
return (pin >= 0 && pin <= 5) || (pin >= 12 && pin <= 15);
|
||||
#elif defined(ESP32)
|
||||
return pin == 0 || pin == 2 || (pin >= 4 && pin <= 5) || (pin >= 12 && pin <= 19) ||
|
||||
(pin >= 21 && pin <= 23) || (pin >= 25 && pin <= 27) || (pin >= 32 && pin <= 35);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SoftwareSerial::begin(uint32_t baud, SoftwareSerialConfig config,
|
||||
int8_t rxPin, int8_t txPin,
|
||||
bool invert, int bufCapacity, int isrBufCapacity) {
|
||||
if (-1 != rxPin) m_rxPin = rxPin;
|
||||
if (-1 != txPin) m_txPin = txPin;
|
||||
m_oneWire = (m_rxPin == m_txPin);
|
||||
m_invert = invert;
|
||||
m_dataBits = 5 + (config & 07);
|
||||
m_parityMode = static_cast<SoftwareSerialParity>(config & 070);
|
||||
m_stopBits = 1 + ((config & 0300) ? 1 : 0);
|
||||
m_pduBits = m_dataBits + static_cast<bool>(m_parityMode) + m_stopBits;
|
||||
m_bitCycles = (ESP.getCpuFreqMHz() * 1000000UL + baud / 2) / baud;
|
||||
m_intTxEnabled = true;
|
||||
if (isValidGPIOpin(m_rxPin)) {
|
||||
std::unique_ptr<circular_queue<uint8_t> > buffer(new circular_queue<uint8_t>((bufCapacity > 0) ? bufCapacity : 64));
|
||||
m_buffer = move(buffer);
|
||||
if (m_parityMode)
|
||||
{
|
||||
std::unique_ptr<circular_queue<uint8_t> > parityBuffer(new circular_queue<uint8_t>((bufCapacity > 0) ? (bufCapacity + 7) / 8 : 8));
|
||||
m_parityBuffer = move(parityBuffer);
|
||||
m_parityInPos = m_parityOutPos = 1;
|
||||
}
|
||||
std::unique_ptr<circular_queue<uint32_t> > isrBuffer(new circular_queue<uint32_t>((isrBufCapacity > 0) ? isrBufCapacity : (sizeof(uint8_t) * 8 + 2) * bufCapacity));
|
||||
m_isrBuffer = move(isrBuffer);
|
||||
if (m_buffer && (!m_parityMode || m_parityBuffer) && m_isrBuffer) {
|
||||
m_rxValid = true;
|
||||
pinMode(m_rxPin, INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
if (isValidGPIOpin(m_txPin)
|
||||
#ifdef ESP8266
|
||||
|| ((m_txPin == 16) && !m_oneWire)) {
|
||||
#else
|
||||
) {
|
||||
#endif
|
||||
m_txValid = true;
|
||||
if (!m_oneWire) {
|
||||
pinMode(m_txPin, OUTPUT);
|
||||
digitalWrite(m_txPin, !m_invert);
|
||||
}
|
||||
}
|
||||
if (!m_rxEnabled) { enableRx(true); }
|
||||
}
|
||||
|
||||
void SoftwareSerial::end()
|
||||
{
|
||||
enableRx(false);
|
||||
m_txValid = false;
|
||||
if (m_buffer) {
|
||||
m_buffer.reset();
|
||||
}
|
||||
m_parityBuffer.reset();
|
||||
if (m_isrBuffer) {
|
||||
m_isrBuffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t SoftwareSerial::baudRate() {
|
||||
return ESP.getCpuFreqMHz() * 1000000UL / m_bitCycles;
|
||||
}
|
||||
|
||||
void SoftwareSerial::setTransmitEnablePin(int8_t txEnablePin) {
|
||||
if (isValidGPIOpin(txEnablePin)) {
|
||||
m_txEnableValid = true;
|
||||
m_txEnablePin = txEnablePin;
|
||||
pinMode(m_txEnablePin, OUTPUT);
|
||||
digitalWrite(m_txEnablePin, LOW);
|
||||
}
|
||||
else {
|
||||
m_txEnableValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareSerial::enableIntTx(bool on) {
|
||||
m_intTxEnabled = on;
|
||||
}
|
||||
|
||||
void SoftwareSerial::enableTx(bool on) {
|
||||
if (m_txValid && m_oneWire) {
|
||||
if (on) {
|
||||
enableRx(false);
|
||||
pinMode(m_txPin, OUTPUT);
|
||||
digitalWrite(m_txPin, !m_invert);
|
||||
}
|
||||
else {
|
||||
pinMode(m_rxPin, INPUT_PULLUP);
|
||||
enableRx(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareSerial::enableRx(bool on) {
|
||||
if (m_rxValid) {
|
||||
if (on) {
|
||||
m_rxCurBit = m_pduBits - 1;
|
||||
// Init to stop bit level and current cycle
|
||||
m_isrLastCycle = (ESP.getCycleCount() | 1) ^ m_invert;
|
||||
if (m_bitCycles >= (ESP.getCpuFreqMHz() * 1000000UL) / 74880UL)
|
||||
attachInterruptArg(digitalPinToInterrupt(m_rxPin), reinterpret_cast<void (*)(void*)>(rxBitISR), this, CHANGE);
|
||||
else
|
||||
attachInterruptArg(digitalPinToInterrupt(m_rxPin), reinterpret_cast<void (*)(void*)>(rxBitSyncISR), this, m_invert ? RISING : FALLING);
|
||||
}
|
||||
else {
|
||||
detachInterrupt(digitalPinToInterrupt(m_rxPin));
|
||||
}
|
||||
m_rxEnabled = on;
|
||||
}
|
||||
}
|
||||
|
||||
int SoftwareSerial::read() {
|
||||
if (!m_rxValid) { return -1; }
|
||||
if (!m_buffer->available()) {
|
||||
rxBits();
|
||||
if (!m_buffer->available()) { return -1; }
|
||||
}
|
||||
auto val = m_buffer->pop();
|
||||
if (m_parityBuffer)
|
||||
{
|
||||
m_lastReadParity = m_parityBuffer->peek() & m_parityOutPos;
|
||||
m_parityOutPos <<= 1;
|
||||
if (!m_parityOutPos)
|
||||
{
|
||||
m_parityOutPos = 1;
|
||||
m_parityBuffer->pop();
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::read(uint8_t * buffer, size_t size) {
|
||||
if (!m_rxValid) { return 0; }
|
||||
size_t avail;
|
||||
if (0 == (avail = m_buffer->pop_n(buffer, size))) {
|
||||
rxBits();
|
||||
avail = m_buffer->pop_n(buffer, size);
|
||||
}
|
||||
if (!avail) return 0;
|
||||
if (m_parityBuffer) {
|
||||
uint32_t parityBits = avail;
|
||||
while (m_parityOutPos >>= 1) ++parityBits;
|
||||
m_parityOutPos = (1 << (parityBits % 8));
|
||||
m_parityBuffer->pop_n(nullptr, parityBits / 8);
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::readBytes(uint8_t * buffer, size_t size) {
|
||||
if (!m_rxValid || !size) { return 0; }
|
||||
size_t count = 0;
|
||||
const auto start = millis();
|
||||
do {
|
||||
count += read(&buffer[count], size - count);
|
||||
if (count >= size) break;
|
||||
yield();
|
||||
} while (millis() - start < _timeout);
|
||||
return count;
|
||||
}
|
||||
|
||||
int SoftwareSerial::available() {
|
||||
if (!m_rxValid) { return 0; }
|
||||
rxBits();
|
||||
int avail = m_buffer->available();
|
||||
if (!avail) {
|
||||
optimistic_yield(10000UL);
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR SoftwareSerial::preciseDelay(bool sync) {
|
||||
if (!sync)
|
||||
{
|
||||
// Reenable interrupts while delaying to avoid other tasks piling up
|
||||
if (!m_intTxEnabled) { xt_wsr_ps(m_savedPS); }
|
||||
auto expired = ESP.getCycleCount() - m_periodStart;
|
||||
if (expired < m_periodDuration)
|
||||
{
|
||||
auto ms = (m_periodDuration - expired) / ESP.getCpuFreqMHz() / 1000UL;
|
||||
if (ms) delay(ms);
|
||||
}
|
||||
while ((ESP.getCycleCount() - m_periodStart) < m_periodDuration) { optimistic_yield(10000); }
|
||||
// Disable interrupts again
|
||||
if (!m_intTxEnabled) { m_savedPS = xt_rsil(15); }
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((ESP.getCycleCount() - m_periodStart) < m_periodDuration) {}
|
||||
}
|
||||
m_periodDuration = 0;
|
||||
m_periodStart = ESP.getCycleCount();
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR SoftwareSerial::writePeriod(
|
||||
uint32_t dutyCycle, uint32_t offCycle, bool withStopBit) {
|
||||
preciseDelay(true);
|
||||
if (dutyCycle)
|
||||
{
|
||||
digitalWrite(m_txPin, HIGH);
|
||||
m_periodDuration += dutyCycle;
|
||||
if (offCycle || (withStopBit && !m_invert)) preciseDelay(!withStopBit || m_invert);
|
||||
}
|
||||
if (offCycle)
|
||||
{
|
||||
digitalWrite(m_txPin, LOW);
|
||||
m_periodDuration += offCycle;
|
||||
if (withStopBit && m_invert) preciseDelay(false);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::write(uint8_t byte) {
|
||||
return write(&byte, 1);
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::write(uint8_t byte, SoftwareSerialParity parity) {
|
||||
return write(&byte, 1, parity);
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::write(const uint8_t * buffer, size_t size) {
|
||||
return write(buffer, size, m_parityMode);
|
||||
}
|
||||
|
||||
size_t ICACHE_RAM_ATTR SoftwareSerial::write(const uint8_t * buffer, size_t size, SoftwareSerialParity parity) {
|
||||
if (m_rxValid) { rxBits(); }
|
||||
if (!m_txValid) { return -1; }
|
||||
|
||||
if (m_txEnableValid) {
|
||||
digitalWrite(m_txEnablePin, HIGH);
|
||||
}
|
||||
// Stop bit: if inverted, LOW, otherwise HIGH
|
||||
bool b = !m_invert;
|
||||
uint32_t dutyCycle = 0;
|
||||
uint32_t offCycle = 0;
|
||||
if (!m_intTxEnabled) {
|
||||
// Disable interrupts in order to get a clean transmit timing
|
||||
m_savedPS = xt_rsil(15);
|
||||
}
|
||||
const uint32_t dataMask = ((1UL << m_dataBits) - 1);
|
||||
bool withStopBit = true;
|
||||
m_periodDuration = 0;
|
||||
m_periodStart = ESP.getCycleCount();
|
||||
for (size_t cnt = 0; cnt < size; ++cnt) {
|
||||
uint8_t byte = ~buffer[cnt] & dataMask;
|
||||
// push LSB start-data-parity-stop bit pattern into uint32_t
|
||||
// Stop bits: HIGH
|
||||
uint32_t word = ~0UL;
|
||||
// parity bit, if any
|
||||
if (parity && m_parityMode)
|
||||
{
|
||||
uint32_t parityBit;
|
||||
switch (parity)
|
||||
{
|
||||
case SWSERIAL_PARITY_EVEN:
|
||||
// from inverted, so use odd parity
|
||||
parityBit = byte;
|
||||
parityBit ^= parityBit >> 4;
|
||||
parityBit &= 0xf;
|
||||
parityBit = (0x9669 >> parityBit) & 1;
|
||||
break;
|
||||
case SWSERIAL_PARITY_ODD:
|
||||
// from inverted, so use even parity
|
||||
parityBit = byte;
|
||||
parityBit ^= parityBit >> 4;
|
||||
parityBit &= 0xf;
|
||||
parityBit = (0x6996 >> parityBit) & 1;
|
||||
break;
|
||||
case SWSERIAL_PARITY_MARK:
|
||||
parityBit = false;
|
||||
break;
|
||||
case SWSERIAL_PARITY_SPACE:
|
||||
// suppresses warning parityBit uninitialized
|
||||
default:
|
||||
parityBit = true;
|
||||
break;
|
||||
}
|
||||
word ^= parityBit << m_dataBits;
|
||||
}
|
||||
word ^= byte;
|
||||
// Stop bit: LOW
|
||||
word <<= 1;
|
||||
if (m_invert) word = ~word;
|
||||
for (int i = 0; i <= m_pduBits; ++i) {
|
||||
bool pb = b;
|
||||
b = word & (1UL << i);
|
||||
if (!pb && b) {
|
||||
writePeriod(dutyCycle, offCycle, withStopBit);
|
||||
withStopBit = false;
|
||||
dutyCycle = offCycle = 0;
|
||||
}
|
||||
if (b) {
|
||||
dutyCycle += m_bitCycles;
|
||||
}
|
||||
else {
|
||||
offCycle += m_bitCycles;
|
||||
}
|
||||
}
|
||||
withStopBit = true;
|
||||
}
|
||||
writePeriod(dutyCycle, offCycle, true);
|
||||
if (!m_intTxEnabled) {
|
||||
// restore the interrupt state
|
||||
xt_wsr_ps(m_savedPS);
|
||||
}
|
||||
if (m_txEnableValid) {
|
||||
digitalWrite(m_txEnablePin, LOW);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void SoftwareSerial::flush() {
|
||||
if (!m_rxValid) { return; }
|
||||
m_buffer->flush();
|
||||
if (m_parityBuffer)
|
||||
{
|
||||
m_parityInPos = m_parityOutPos = 1;
|
||||
m_parityBuffer->flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool SoftwareSerial::overflow() {
|
||||
bool res = m_overflow;
|
||||
m_overflow = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
int SoftwareSerial::peek() {
|
||||
if (!m_rxValid) { return -1; }
|
||||
if (!m_buffer->available()) {
|
||||
rxBits();
|
||||
if (!m_buffer->available()) return -1;
|
||||
}
|
||||
auto val = m_buffer->peek();
|
||||
if (m_parityBuffer) m_lastReadParity = m_parityBuffer->peek() & m_parityOutPos;
|
||||
return val;
|
||||
}
|
||||
|
||||
void SoftwareSerial::rxBits() {
|
||||
int isrAvail = m_isrBuffer->available();
|
||||
#ifdef ESP8266
|
||||
if (m_isrOverflow.load()) {
|
||||
m_overflow = true;
|
||||
m_isrOverflow.store(false);
|
||||
}
|
||||
#else
|
||||
if (m_isrOverflow.exchange(false)) {
|
||||
m_overflow = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// stop bit can go undetected if leading data bits are at same level
|
||||
// and there was also no next start bit yet, so one byte may be pending.
|
||||
// low-cost check first
|
||||
if (!isrAvail && m_rxCurBit >= -1 && m_rxCurBit < m_pduBits - m_stopBits) {
|
||||
uint32_t detectionCycles = (m_pduBits - m_stopBits - m_rxCurBit) * m_bitCycles;
|
||||
if (ESP.getCycleCount() - m_isrLastCycle > detectionCycles) {
|
||||
// Produce faux stop bit level, prevents start bit maldetection
|
||||
// cycle's LSB is repurposed for the level bit
|
||||
rxBits(((m_isrLastCycle + detectionCycles) | 1) ^ m_invert);
|
||||
}
|
||||
}
|
||||
|
||||
m_isrBuffer->for_each([this](const uint32_t& isrCycle) { rxBits(isrCycle); });
|
||||
}
|
||||
|
||||
void SoftwareSerial::rxBits(const uint32_t & isrCycle) {
|
||||
bool level = (m_isrLastCycle & 1) ^ m_invert;
|
||||
|
||||
// error introduced by edge value in LSB of isrCycle is negligible
|
||||
int32_t cycles = isrCycle - m_isrLastCycle;
|
||||
m_isrLastCycle = isrCycle;
|
||||
|
||||
uint8_t bits = cycles / m_bitCycles;
|
||||
if (cycles % m_bitCycles > (m_bitCycles >> 1)) ++bits;
|
||||
while (bits > 0) {
|
||||
// start bit detection
|
||||
if (m_rxCurBit >= (m_pduBits - 1)) {
|
||||
// leading edge of start bit
|
||||
if (level) break;
|
||||
m_rxCurBit = -1;
|
||||
--bits;
|
||||
continue;
|
||||
}
|
||||
// data bits
|
||||
if (m_rxCurBit >= -1 && m_rxCurBit < (m_dataBits - 1)) {
|
||||
int8_t dataBits = min(bits, static_cast<uint8_t>(m_dataBits - 1 - m_rxCurBit));
|
||||
m_rxCurBit += dataBits;
|
||||
bits -= dataBits;
|
||||
m_rxCurByte >>= dataBits;
|
||||
if (level) { m_rxCurByte |= (BYTE_ALL_BITS_SET << (8 - dataBits)); }
|
||||
continue;
|
||||
}
|
||||
// parity bit
|
||||
if (m_parityMode && m_rxCurBit == (m_dataBits - 1)) {
|
||||
++m_rxCurBit;
|
||||
--bits;
|
||||
m_rxCurParity = level;
|
||||
continue;
|
||||
}
|
||||
// stop bits
|
||||
if (m_rxCurBit < (m_pduBits - m_stopBits - 1)) {
|
||||
++m_rxCurBit;
|
||||
--bits;
|
||||
continue;
|
||||
}
|
||||
if (m_rxCurBit == (m_pduBits - m_stopBits - 1)) {
|
||||
// Store the received value in the buffer unless we have an overflow
|
||||
// if not high stop bit level, discard word
|
||||
if (level)
|
||||
{
|
||||
m_rxCurByte >>= (sizeof(uint8_t) * 8 - m_dataBits);
|
||||
if (!m_buffer->push(m_rxCurByte)) {
|
||||
m_overflow = true;
|
||||
}
|
||||
else {
|
||||
if (m_parityBuffer)
|
||||
{
|
||||
if (m_rxCurParity) {
|
||||
m_parityBuffer->pushpeek() |= m_parityInPos;
|
||||
}
|
||||
else {
|
||||
m_parityBuffer->pushpeek() &= ~m_parityInPos;
|
||||
}
|
||||
m_parityInPos <<= 1;
|
||||
if (!m_parityInPos)
|
||||
{
|
||||
m_parityBuffer->push();
|
||||
m_parityInPos = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_rxCurBit = m_pduBits;
|
||||
// reset to 0 is important for masked bit logic
|
||||
m_rxCurByte = 0;
|
||||
m_rxCurParity = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR SoftwareSerial::rxBitISR(SoftwareSerial * self) {
|
||||
uint32_t curCycle = ESP.getCycleCount();
|
||||
bool level = digitalRead(self->m_rxPin);
|
||||
|
||||
// Store level and cycle in the buffer unless we have an overflow
|
||||
// cycle's LSB is repurposed for the level bit
|
||||
if (!self->m_isrBuffer->push((curCycle | 1U) ^ !level)) self->m_isrOverflow.store(true);
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR SoftwareSerial::rxBitSyncISR(SoftwareSerial * self) {
|
||||
uint32_t start = ESP.getCycleCount();
|
||||
uint32_t wait = self->m_bitCycles - 172U;
|
||||
|
||||
bool level = self->m_invert;
|
||||
// Store level and cycle in the buffer unless we have an overflow
|
||||
// cycle's LSB is repurposed for the level bit
|
||||
if (!self->m_isrBuffer->push(((start + wait) | 1U) ^ !level)) self->m_isrOverflow.store(true);
|
||||
|
||||
for (uint32_t i = 0; i < self->m_pduBits; ++i) {
|
||||
while (ESP.getCycleCount() - start < wait) {};
|
||||
wait += self->m_bitCycles;
|
||||
|
||||
// Store level and cycle in the buffer unless we have an overflow
|
||||
// cycle's LSB is repurposed for the level bit
|
||||
if (digitalRead(self->m_rxPin) != level)
|
||||
{
|
||||
if (!self->m_isrBuffer->push(((start + wait) | 1U) ^ level)) self->m_isrOverflow.store(true);
|
||||
level = !level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftwareSerial::onReceive(Delegate<void(int available), void*> handler) {
|
||||
receiveHandler = handler;
|
||||
}
|
||||
|
||||
void SoftwareSerial::perform_work() {
|
||||
if (!m_rxValid) { return; }
|
||||
rxBits();
|
||||
if (receiveHandler) {
|
||||
int avail = m_buffer->available();
|
||||
if (avail) { receiveHandler(avail); }
|
||||
}
|
||||
}
|
@ -1,255 +0,0 @@
|
||||
/*
|
||||
SoftwareSerial.h
|
||||
|
||||
SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266/ESP32.
|
||||
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
|
||||
Copyright (c) 2018-2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SoftwareSerial_h
|
||||
#define __SoftwareSerial_h
|
||||
|
||||
#include "circular_queue/circular_queue.h"
|
||||
#include <Stream.h>
|
||||
|
||||
enum SoftwareSerialParity : uint8_t {
|
||||
SWSERIAL_PARITY_NONE = 000,
|
||||
SWSERIAL_PARITY_EVEN = 020,
|
||||
SWSERIAL_PARITY_ODD = 030,
|
||||
SWSERIAL_PARITY_MARK = 040,
|
||||
SWSERIAL_PARITY_SPACE = 070,
|
||||
};
|
||||
|
||||
enum SoftwareSerialConfig {
|
||||
SWSERIAL_5N1 = SWSERIAL_PARITY_NONE,
|
||||
SWSERIAL_6N1,
|
||||
SWSERIAL_7N1,
|
||||
SWSERIAL_8N1,
|
||||
SWSERIAL_5E1 = SWSERIAL_PARITY_EVEN,
|
||||
SWSERIAL_6E1,
|
||||
SWSERIAL_7E1,
|
||||
SWSERIAL_8E1,
|
||||
SWSERIAL_5O1 = SWSERIAL_PARITY_ODD,
|
||||
SWSERIAL_6O1,
|
||||
SWSERIAL_7O1,
|
||||
SWSERIAL_8O1,
|
||||
SWSERIAL_5M1 = SWSERIAL_PARITY_MARK,
|
||||
SWSERIAL_6M1,
|
||||
SWSERIAL_7M1,
|
||||
SWSERIAL_8M1,
|
||||
SWSERIAL_5S1 = SWSERIAL_PARITY_SPACE,
|
||||
SWSERIAL_6S1,
|
||||
SWSERIAL_7S1,
|
||||
SWSERIAL_8S1,
|
||||
SWSERIAL_5N2 = 0200 | SWSERIAL_PARITY_NONE,
|
||||
SWSERIAL_6N2,
|
||||
SWSERIAL_7N2,
|
||||
SWSERIAL_8N2,
|
||||
SWSERIAL_5E2 = 0200 | SWSERIAL_PARITY_EVEN,
|
||||
SWSERIAL_6E2,
|
||||
SWSERIAL_7E2,
|
||||
SWSERIAL_8E2,
|
||||
SWSERIAL_5O2 = 0200 | SWSERIAL_PARITY_ODD,
|
||||
SWSERIAL_6O2,
|
||||
SWSERIAL_7O2,
|
||||
SWSERIAL_8O2,
|
||||
SWSERIAL_5M2 = 0200 | SWSERIAL_PARITY_MARK,
|
||||
SWSERIAL_6M2,
|
||||
SWSERIAL_7M2,
|
||||
SWSERIAL_8M2,
|
||||
SWSERIAL_5S2 = 0200 | SWSERIAL_PARITY_SPACE,
|
||||
SWSERIAL_6S2,
|
||||
SWSERIAL_7S2,
|
||||
SWSERIAL_8S2,
|
||||
};
|
||||
|
||||
/// This class is compatible with the corresponding AVR one, however,
|
||||
/// the constructor takes no arguments, for compatibility with the
|
||||
/// HardwareSerial class.
|
||||
/// Instead, the begin() function handles pin assignments and logic inversion.
|
||||
/// It also has optional input buffer capacity arguments for byte buffer and ISR bit buffer.
|
||||
/// Bitrates up to at least 115200 can be used.
|
||||
class SoftwareSerial : public Stream {
|
||||
public:
|
||||
SoftwareSerial();
|
||||
/// Ctor to set defaults for pins.
|
||||
/// @param rxPin the GPIO pin used for RX
|
||||
/// @param txPin -1 for onewire protocol, GPIO pin used for twowire TX
|
||||
SoftwareSerial(int8_t rxPin, int8_t txPin = -1, bool invert = false);
|
||||
SoftwareSerial(const SoftwareSerial&) = delete;
|
||||
SoftwareSerial& operator= (const SoftwareSerial&) = delete;
|
||||
virtual ~SoftwareSerial();
|
||||
/// Configure the SoftwareSerial object for use.
|
||||
/// @param baud the TX/RX bitrate
|
||||
/// @param config sets databits, parity, and stop bit count
|
||||
/// @param rxPin -1 or default: either no RX pin, or keeps the rxPin set in the ctor
|
||||
/// @param txPin -1 or default: either no TX pin (onewire), or keeps the txPin set in the ctor
|
||||
/// @param invert true: uses invert line level logic
|
||||
/// @param bufCapacity the capacity for the received bytes buffer
|
||||
/// @param isrBufCapacity 0: derived from bufCapacity. The capacity of the internal asynchronous
|
||||
/// bit receive buffer, a suggested size is bufCapacity times the sum of
|
||||
/// start, data, parity and stop bit count.
|
||||
void begin(uint32_t baud, SoftwareSerialConfig config,
|
||||
int8_t rxPin, int8_t txPin, bool invert,
|
||||
int bufCapacity = 64, int isrBufCapacity = 0);
|
||||
void begin(uint32_t baud, SoftwareSerialConfig config,
|
||||
int8_t rxPin, int8_t txPin) {
|
||||
begin(baud, config, rxPin, txPin, m_invert);
|
||||
}
|
||||
void begin(uint32_t baud, SoftwareSerialConfig config,
|
||||
int8_t rxPin) {
|
||||
begin(baud, config, rxPin, m_txPin, m_invert);
|
||||
}
|
||||
void begin(uint32_t baud, SoftwareSerialConfig config = SWSERIAL_8N1) {
|
||||
begin(baud, config, m_rxPin, m_txPin, m_invert);
|
||||
}
|
||||
|
||||
uint32_t baudRate();
|
||||
/// Transmit control pin.
|
||||
void setTransmitEnablePin(int8_t txEnablePin);
|
||||
/// Enable or disable interrupts during tx.
|
||||
void enableIntTx(bool on);
|
||||
|
||||
bool overflow();
|
||||
|
||||
int available() override;
|
||||
int availableForWrite() {
|
||||
if (!m_txValid) return 0;
|
||||
return 1;
|
||||
}
|
||||
int peek() override;
|
||||
int read() override;
|
||||
/// @returns The verbatim parity bit associated with the last read() or peek() call
|
||||
bool readParity()
|
||||
{
|
||||
return m_lastReadParity;
|
||||
}
|
||||
/// @returns The calculated bit for even parity of the parameter byte
|
||||
static bool parityEven(uint8_t byte) {
|
||||
byte ^= byte >> 4;
|
||||
byte &= 0xf;
|
||||
return (0x6996 >> byte) & 1;
|
||||
}
|
||||
/// @returns The calculated bit for odd parity of the parameter byte
|
||||
static bool parityOdd(uint8_t byte) {
|
||||
byte ^= byte >> 4;
|
||||
byte &= 0xf;
|
||||
return (0x9669 >> byte) & 1;
|
||||
}
|
||||
/// The read(buffer, size) functions are non-blocking, the same as readBytes but without timeout
|
||||
size_t read(uint8_t* buffer, size_t size);
|
||||
/// The read(buffer, size) functions are non-blocking, the same as readBytes but without timeout
|
||||
size_t read(char* buffer, size_t size) {
|
||||
return read(reinterpret_cast<uint8_t*>(buffer), size);
|
||||
}
|
||||
/// @returns The number of bytes read into buffer, up to size. Times out if the limit set through
|
||||
/// Stream::setTimeout() is reached.
|
||||
size_t readBytes(uint8_t* buffer, size_t size) override;
|
||||
/// @returns The number of bytes read into buffer, up to size. Times out if the limit set through
|
||||
/// Stream::setTimeout() is reached.
|
||||
size_t readBytes(char* buffer, size_t size) override {
|
||||
return readBytes(reinterpret_cast<uint8_t*>(buffer), size);
|
||||
}
|
||||
void flush() override;
|
||||
size_t write(uint8_t byte) override;
|
||||
size_t write(uint8_t byte, SoftwareSerialParity parity);
|
||||
size_t write(const uint8_t* buffer, size_t size) override;
|
||||
size_t write(const char* buffer, size_t size) {
|
||||
return write(reinterpret_cast<const uint8_t*>(buffer), size);
|
||||
}
|
||||
size_t write(const uint8_t* buffer, size_t size, SoftwareSerialParity parity);
|
||||
size_t write(const char* buffer, size_t size, SoftwareSerialParity parity) {
|
||||
return write(reinterpret_cast<const uint8_t*>(buffer), size, parity);
|
||||
}
|
||||
operator bool() const { return m_rxValid || m_txValid; }
|
||||
|
||||
/// Disable or enable interrupts on the rx pin.
|
||||
void enableRx(bool on);
|
||||
/// One wire control.
|
||||
void enableTx(bool on);
|
||||
|
||||
// AVR compatibility methods.
|
||||
bool listen() { enableRx(true); return true; }
|
||||
void end();
|
||||
bool isListening() { return m_rxEnabled; }
|
||||
bool stopListening() { enableRx(false); return true; }
|
||||
|
||||
/// Set an event handler for received data.
|
||||
void onReceive(Delegate<void(int available), void*> handler);
|
||||
|
||||
/// Run the internal processing and event engine. Can be iteratively called
|
||||
/// from loop, or otherwise scheduled.
|
||||
void perform_work();
|
||||
|
||||
using Print::write;
|
||||
|
||||
private:
|
||||
// If sync is false, it's legal to exceed the deadline, for instance,
|
||||
// by enabling interrupts.
|
||||
void preciseDelay(bool sync);
|
||||
// If withStopBit is set, either cycle contains a stop bit.
|
||||
// If dutyCycle == 0, the level is not forced to HIGH.
|
||||
// If offCycle == 0, the level remains unchanged from dutyCycle.
|
||||
void writePeriod(
|
||||
uint32_t dutyCycle, uint32_t offCycle, bool withStopBit);
|
||||
bool isValidGPIOpin(int8_t pin);
|
||||
/* check m_rxValid that calling is safe */
|
||||
void rxBits();
|
||||
void rxBits(const uint32_t& isrCycle);
|
||||
|
||||
static void rxBitISR(SoftwareSerial* self);
|
||||
static void rxBitSyncISR(SoftwareSerial* self);
|
||||
|
||||
// Member variables
|
||||
int8_t m_rxPin = -1;
|
||||
int8_t m_txPin = -1;
|
||||
int8_t m_txEnablePin = -1;
|
||||
uint8_t m_dataBits;
|
||||
bool m_oneWire;
|
||||
bool m_rxValid = false;
|
||||
bool m_rxEnabled = false;
|
||||
bool m_txValid = false;
|
||||
bool m_txEnableValid = false;
|
||||
bool m_invert;
|
||||
/// PDU bits include data, parity and stop bits; the start bit is not counted.
|
||||
uint8_t m_pduBits;
|
||||
bool m_intTxEnabled;
|
||||
SoftwareSerialParity m_parityMode;
|
||||
uint8_t m_stopBits;
|
||||
bool m_lastReadParity;
|
||||
bool m_overflow = false;
|
||||
uint32_t m_bitCycles;
|
||||
uint8_t m_parityInPos;
|
||||
uint8_t m_parityOutPos;
|
||||
int8_t m_rxCurBit; // 0 thru (m_pduBits - m_stopBits - 1): data/parity bits. -1: start bit. (m_pduBits - 1): stop bit.
|
||||
uint8_t m_rxCurByte = 0;
|
||||
std::unique_ptr<circular_queue<uint8_t> > m_buffer;
|
||||
std::unique_ptr<circular_queue<uint8_t> > m_parityBuffer;
|
||||
uint32_t m_periodStart;
|
||||
uint32_t m_periodDuration;
|
||||
uint32_t m_savedPS = 0;
|
||||
// the ISR stores the relative bit times in the buffer. The inversion corrected level is used as sign bit (2's complement):
|
||||
// 1 = positive including 0, 0 = negative.
|
||||
std::unique_ptr<circular_queue<uint32_t> > m_isrBuffer;
|
||||
std::atomic<bool> m_isrOverflow;
|
||||
uint32_t m_isrLastCycle;
|
||||
bool m_rxCurParity = false;
|
||||
Delegate<void(int available), void*> receiveHandler;
|
||||
};
|
||||
|
||||
#endif // __SoftwareSerial_h
|
File diff suppressed because it is too large
Load Diff
@ -1,503 +0,0 @@
|
||||
/*
|
||||
MultiDelegate.h - A queue or event multiplexer based on the efficient Delegate
|
||||
class
|
||||
Copyright (c) 2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __MULTIDELEGATE_H
|
||||
#define __MULTIDELEGATE_H
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
#include <atomic>
|
||||
#else
|
||||
#include "circular_queue/ghostl.h"
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
#include <interrupts.h>
|
||||
using esp8266::InterruptLock;
|
||||
#elif defined(ARDUINO)
|
||||
class InterruptLock {
|
||||
public:
|
||||
InterruptLock() {
|
||||
noInterrupts();
|
||||
}
|
||||
~InterruptLock() {
|
||||
interrupts();
|
||||
}
|
||||
};
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template< typename Delegate, typename R, bool ISQUEUE = false, typename... P>
|
||||
struct CallP
|
||||
{
|
||||
static R execute(Delegate& del, P... args)
|
||||
{
|
||||
return del(std::forward<P...>(args...)) ? !ISQUEUE : ISQUEUE;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Delegate, bool ISQUEUE, typename... P>
|
||||
struct CallP<Delegate, void, ISQUEUE, P...>
|
||||
{
|
||||
static bool execute(Delegate& del, P... args)
|
||||
{
|
||||
del(std::forward<P...>(args...));
|
||||
return !ISQUEUE;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Delegate, typename R, bool ISQUEUE = false>
|
||||
struct Call
|
||||
{
|
||||
static R execute(Delegate& del)
|
||||
{
|
||||
return del() ? !ISQUEUE : ISQUEUE;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Delegate, bool ISQUEUE>
|
||||
struct Call<Delegate, void, ISQUEUE>
|
||||
{
|
||||
static bool execute(Delegate& del)
|
||||
{
|
||||
del();
|
||||
return !ISQUEUE;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32, typename... P>
|
||||
class MultiDelegatePImpl
|
||||
{
|
||||
public:
|
||||
MultiDelegatePImpl() = default;
|
||||
~MultiDelegatePImpl()
|
||||
{
|
||||
*this = nullptr;
|
||||
}
|
||||
|
||||
MultiDelegatePImpl(const MultiDelegatePImpl&) = delete;
|
||||
MultiDelegatePImpl& operator=(const MultiDelegatePImpl&) = delete;
|
||||
|
||||
MultiDelegatePImpl(MultiDelegatePImpl&& md)
|
||||
{
|
||||
first = md.first;
|
||||
last = md.last;
|
||||
unused = md.unused;
|
||||
nodeCount = md.nodeCount;
|
||||
md.first = nullptr;
|
||||
md.last = nullptr;
|
||||
md.unused = nullptr;
|
||||
md.nodeCount = 0;
|
||||
}
|
||||
|
||||
MultiDelegatePImpl(const Delegate& del)
|
||||
{
|
||||
add(del);
|
||||
}
|
||||
|
||||
MultiDelegatePImpl(Delegate&& del)
|
||||
{
|
||||
add(std::move(del));
|
||||
}
|
||||
|
||||
MultiDelegatePImpl& operator=(MultiDelegatePImpl&& md)
|
||||
{
|
||||
first = md.first;
|
||||
last = md.last;
|
||||
unused = md.unused;
|
||||
nodeCount = md.nodeCount;
|
||||
md.first = nullptr;
|
||||
md.last = nullptr;
|
||||
md.unused = nullptr;
|
||||
md.nodeCount = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultiDelegatePImpl& operator=(std::nullptr_t)
|
||||
{
|
||||
if (last)
|
||||
last->mNext = unused;
|
||||
if (first)
|
||||
unused = first;
|
||||
while (unused)
|
||||
{
|
||||
auto to_delete = unused;
|
||||
unused = unused->mNext;
|
||||
delete(to_delete);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultiDelegatePImpl& operator+=(const Delegate& del)
|
||||
{
|
||||
add(del);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MultiDelegatePImpl& operator+=(Delegate&& del)
|
||||
{
|
||||
add(std::move(del));
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct Node_t
|
||||
{
|
||||
~Node_t()
|
||||
{
|
||||
mDelegate = nullptr; // special overload in Delegate
|
||||
}
|
||||
Node_t* mNext = nullptr;
|
||||
Delegate mDelegate;
|
||||
};
|
||||
|
||||
Node_t* first = nullptr;
|
||||
Node_t* last = nullptr;
|
||||
Node_t* unused = nullptr;
|
||||
uint32_t nodeCount = 0;
|
||||
|
||||
// Returns a pointer to an unused Node_t,
|
||||
// or if none are available allocates a new one,
|
||||
// or nullptr if limit is reached
|
||||
Node_t* IRAM_ATTR get_node_unsafe()
|
||||
{
|
||||
Node_t* result = nullptr;
|
||||
// try to get an item from unused items list
|
||||
if (unused)
|
||||
{
|
||||
result = unused;
|
||||
unused = unused->mNext;
|
||||
}
|
||||
// if no unused items, and count not too high, allocate a new one
|
||||
else if (nodeCount < QUEUE_CAPACITY)
|
||||
{
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
result = new (std::nothrow) Node_t;
|
||||
#else
|
||||
result = new Node_t;
|
||||
#endif
|
||||
if (result)
|
||||
++nodeCount;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void recycle_node_unsafe(Node_t* node)
|
||||
{
|
||||
node->mDelegate = nullptr; // special overload in Delegate
|
||||
node->mNext = unused;
|
||||
unused = node;
|
||||
}
|
||||
|
||||
#ifndef ARDUINO
|
||||
std::mutex mutex_unused;
|
||||
#endif
|
||||
public:
|
||||
const Delegate* IRAM_ATTR add(const Delegate& del)
|
||||
{
|
||||
return add(Delegate(del));
|
||||
}
|
||||
|
||||
const Delegate* IRAM_ATTR add(Delegate&& del)
|
||||
{
|
||||
if (!del)
|
||||
return nullptr;
|
||||
|
||||
#ifdef ARDUINO
|
||||
InterruptLock lockAllInterruptsInThisScope;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(mutex_unused);
|
||||
#endif
|
||||
|
||||
Node_t* item = ISQUEUE ? get_node_unsafe() :
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
new (std::nothrow) Node_t;
|
||||
#else
|
||||
new Node_t;
|
||||
#endif
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
item->mDelegate = std::move(del);
|
||||
item->mNext = nullptr;
|
||||
|
||||
if (last)
|
||||
last->mNext = item;
|
||||
else
|
||||
first = item;
|
||||
last = item;
|
||||
|
||||
return &item->mDelegate;
|
||||
}
|
||||
|
||||
bool remove(const Delegate* del)
|
||||
{
|
||||
auto current = first;
|
||||
if (!current)
|
||||
return false;
|
||||
|
||||
Node_t* prev = nullptr;
|
||||
do
|
||||
{
|
||||
if (del == ¤t->mDelegate)
|
||||
{
|
||||
// remove callback from stack
|
||||
#ifdef ARDUINO
|
||||
InterruptLock lockAllInterruptsInThisScope;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(mutex_unused);
|
||||
#endif
|
||||
|
||||
auto to_recycle = current;
|
||||
|
||||
// removing rLast
|
||||
if (last == current)
|
||||
last = prev;
|
||||
|
||||
current = current->mNext;
|
||||
if (prev)
|
||||
{
|
||||
prev->mNext = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = current;
|
||||
}
|
||||
|
||||
if (ISQUEUE)
|
||||
recycle_node_unsafe(to_recycle);
|
||||
else
|
||||
delete to_recycle;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = current;
|
||||
current = current->mNext;
|
||||
}
|
||||
} while (current);
|
||||
return false;
|
||||
}
|
||||
|
||||
void operator()(P... args)
|
||||
{
|
||||
auto current = first;
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
static std::atomic<bool> fence(false);
|
||||
// prevent recursive calls
|
||||
#if defined(ARDUINO) && !defined(ESP32)
|
||||
if (fence.load()) return;
|
||||
fence.store(true);
|
||||
#else
|
||||
if (fence.exchange(true)) return;
|
||||
#endif
|
||||
|
||||
Node_t* prev = nullptr;
|
||||
// prevent execution of new callbacks during this run
|
||||
auto stop = last;
|
||||
|
||||
bool done;
|
||||
do
|
||||
{
|
||||
done = current == stop;
|
||||
if (!CallP<Delegate, R, ISQUEUE, P...>::execute(current->mDelegate, args...))
|
||||
{
|
||||
// remove callback from stack
|
||||
#ifdef ARDUINO
|
||||
InterruptLock lockAllInterruptsInThisScope;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(mutex_unused);
|
||||
#endif
|
||||
|
||||
auto to_recycle = current;
|
||||
|
||||
// removing rLast
|
||||
if (last == current)
|
||||
last = prev;
|
||||
|
||||
current = current->mNext;
|
||||
if (prev)
|
||||
{
|
||||
prev->mNext = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = current;
|
||||
}
|
||||
|
||||
if (ISQUEUE)
|
||||
recycle_node_unsafe(to_recycle);
|
||||
else
|
||||
delete to_recycle;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = current;
|
||||
current = current->mNext;
|
||||
}
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
// running callbacks might last too long for watchdog etc.
|
||||
optimistic_yield(10000);
|
||||
#endif
|
||||
} while (current && !done);
|
||||
|
||||
fence.store(false);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Delegate, typename R = void, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32>
|
||||
class MultiDelegateImpl : public MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>
|
||||
{
|
||||
protected:
|
||||
using typename MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::Node_t;
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::first;
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::last;
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::unused;
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::nodeCount;
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::recycle_node_unsafe;
|
||||
#ifndef ARDUINO
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::mutex_unused;
|
||||
#endif
|
||||
|
||||
public:
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::MultiDelegatePImpl;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
auto current = first;
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
static std::atomic<bool> fence(false);
|
||||
// prevent recursive calls
|
||||
#if defined(ARDUINO) && !defined(ESP32)
|
||||
if (fence.load()) return;
|
||||
fence.store(true);
|
||||
#else
|
||||
if (fence.exchange(true)) return;
|
||||
#endif
|
||||
|
||||
Node_t* prev = nullptr;
|
||||
// prevent execution of new callbacks during this run
|
||||
auto stop = last;
|
||||
|
||||
bool done;
|
||||
do
|
||||
{
|
||||
done = current == stop;
|
||||
if (!Call<Delegate, R, ISQUEUE>::execute(current->mDelegate))
|
||||
{
|
||||
// remove callback from stack
|
||||
#ifdef ARDUINO
|
||||
InterruptLock lockAllInterruptsInThisScope;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(mutex_unused);
|
||||
#endif
|
||||
|
||||
auto to_recycle = current;
|
||||
|
||||
// removing rLast
|
||||
if (last == current)
|
||||
last = prev;
|
||||
|
||||
current = current->mNext;
|
||||
if (prev)
|
||||
{
|
||||
prev->mNext = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = current;
|
||||
}
|
||||
|
||||
if (ISQUEUE)
|
||||
recycle_node_unsafe(to_recycle);
|
||||
else
|
||||
delete to_recycle;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = current;
|
||||
current = current->mNext;
|
||||
}
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
// running callbacks might last too long for watchdog etc.
|
||||
optimistic_yield(10000);
|
||||
#endif
|
||||
} while (current && !done);
|
||||
|
||||
fence.store(false);
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P> class MultiDelegate;
|
||||
|
||||
template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY, typename... P>
|
||||
class MultiDelegate<Delegate, R(P...), ISQUEUE, QUEUE_CAPACITY> : public MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY, P...>
|
||||
{
|
||||
public:
|
||||
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY, P...>::MultiDelegatePImpl;
|
||||
};
|
||||
|
||||
template< typename Delegate, typename R, bool ISQUEUE, uint32_t QUEUE_CAPACITY>
|
||||
class MultiDelegate<Delegate, R(), ISQUEUE, QUEUE_CAPACITY> : public MultiDelegateImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>
|
||||
{
|
||||
public:
|
||||
using MultiDelegateImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::MultiDelegateImpl;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
The MultiDelegate class template can be specialized to either a queue or an event multiplexer.
|
||||
It is designed to be used with Delegate, the efficient runtime wrapper for C function ptr and C++ std::function.
|
||||
@tparam Delegate specifies the concrete type that MultiDelegate bases the queue or event multiplexer on.
|
||||
@tparam ISQUEUE modifies the generated MultiDelegate class in subtle ways. In queue mode (ISQUEUE == true),
|
||||
the value of QUEUE_CAPACITY enforces the maximum number of simultaneous items the queue can contain.
|
||||
This is exploited to minimize the use of new and delete by reusing already allocated items, thus
|
||||
reducing heap fragmentation. In event multiplexer mode (ISQUEUE = false), new and delete are
|
||||
used for allocation of the event handler items.
|
||||
If the result type of the function call operator of Delegate is void, calling a MultiDelegate queue
|
||||
removes each item after calling it; a Multidelegate event multiplexer keeps event handlers until
|
||||
explicitly removed.
|
||||
If the result type of the function call operator of Delegate is non-void, the type-conversion to bool
|
||||
of that result determines if the item is immediately removed or kept after each call: a Multidelegate
|
||||
queue removes an item only if true is returned, but a Multidelegate event multiplexer removes event
|
||||
handlers that return false.
|
||||
@tparam QUEUE_CAPACITY is only used if ISQUEUE == true. Then, it sets the maximum capacity that the queue dynamically
|
||||
allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate
|
||||
instance during its own lifetime for efficiency.
|
||||
*/
|
||||
template< typename Delegate, bool ISQUEUE = false, uint32_t QUEUE_CAPACITY = 32>
|
||||
class MultiDelegate : public detail::MultiDelegate<Delegate, typename Delegate::target_type, ISQUEUE, QUEUE_CAPACITY>
|
||||
{
|
||||
public:
|
||||
using detail::MultiDelegate<Delegate, typename Delegate::target_type, ISQUEUE, QUEUE_CAPACITY>::MultiDelegate;
|
||||
};
|
||||
|
||||
#endif // __MULTIDELEGATE_H
|
@ -1,399 +0,0 @@
|
||||
/*
|
||||
circular_queue.h - Implementation of a lock-free circular queue for EspSoftwareSerial.
|
||||
Copyright (c) 2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __circular_queue_h
|
||||
#define __circular_queue_h
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include "Delegate.h"
|
||||
using std::min;
|
||||
#else
|
||||
#include "ghostl.h"
|
||||
#endif
|
||||
|
||||
#if !defined(ESP32) && !defined(ESP8266)
|
||||
#define ICACHE_RAM_ATTR
|
||||
#define IRAM_ATTR
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Instance class for a single-producer, single-consumer circular queue / ring buffer (FIFO).
|
||||
This implementation is lock-free between producer and consumer for the available(), peek(),
|
||||
pop(), and push() type functions.
|
||||
*/
|
||||
template< typename T, typename ForEachArg = void >
|
||||
class circular_queue
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
@brief Constructs a valid, but zero-capacity dummy queue.
|
||||
*/
|
||||
circular_queue() : m_bufSize(1)
|
||||
{
|
||||
m_inPos.store(0);
|
||||
m_outPos.store(0);
|
||||
}
|
||||
/*!
|
||||
@brief Constructs a queue of the given maximum capacity.
|
||||
*/
|
||||
circular_queue(const size_t capacity) : m_bufSize(capacity + 1), m_buffer(new T[m_bufSize])
|
||||
{
|
||||
m_inPos.store(0);
|
||||
m_outPos.store(0);
|
||||
}
|
||||
circular_queue(circular_queue&& cq) :
|
||||
m_bufSize(cq.m_bufSize), m_buffer(cq.m_buffer), m_inPos(cq.m_inPos.load()), m_outPos(cq.m_outPos.load())
|
||||
{}
|
||||
~circular_queue()
|
||||
{
|
||||
m_buffer.reset();
|
||||
}
|
||||
circular_queue(const circular_queue&) = delete;
|
||||
circular_queue& operator=(circular_queue&& cq)
|
||||
{
|
||||
m_bufSize = cq.m_bufSize;
|
||||
m_buffer = cq.m_buffer;
|
||||
m_inPos.store(cq.m_inPos.load());
|
||||
m_outPos.store(cq.m_outPos.load());
|
||||
}
|
||||
circular_queue& operator=(const circular_queue&) = delete;
|
||||
|
||||
/*!
|
||||
@brief Get the numer of elements the queue can hold at most.
|
||||
*/
|
||||
size_t capacity() const
|
||||
{
|
||||
return m_bufSize - 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Resize the queue. The available elements in the queue are preserved.
|
||||
This is not lock-free and concurrent producer or consumer access
|
||||
will lead to corruption.
|
||||
@return True if the new capacity could accommodate the present elements in
|
||||
the queue, otherwise nothing is done and false is returned.
|
||||
*/
|
||||
bool capacity(const size_t cap);
|
||||
|
||||
/*!
|
||||
@brief Discard all data in the queue.
|
||||
*/
|
||||
void flush()
|
||||
{
|
||||
m_outPos.store(m_inPos.load());
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get a snapshot number of elements that can be retrieved by pop.
|
||||
*/
|
||||
size_t available() const
|
||||
{
|
||||
int avail = static_cast<int>(m_inPos.load() - m_outPos.load());
|
||||
if (avail < 0) avail += m_bufSize;
|
||||
return avail;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Get the remaining free elementes for pushing.
|
||||
*/
|
||||
size_t available_for_push() const
|
||||
{
|
||||
int avail = static_cast<int>(m_outPos.load() - m_inPos.load()) - 1;
|
||||
if (avail < 0) avail += m_bufSize;
|
||||
return avail;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Peek at the next element pop will return without removing it from the queue.
|
||||
@return An rvalue copy of the next element that can be popped. If the queue is empty,
|
||||
return an rvalue copy of the element that is pending the next push.
|
||||
*/
|
||||
T peek() const
|
||||
{
|
||||
const auto outPos = m_outPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return m_buffer[outPos];
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Peek at the next pending input value.
|
||||
@return A reference to the next element that can be pushed.
|
||||
*/
|
||||
T& IRAM_ATTR pushpeek()
|
||||
{
|
||||
const auto inPos = m_inPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return m_buffer[inPos];
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Release the next pending input value, accessible by pushpeek(), into the queue.
|
||||
@return true if the queue accepted the value, false if the queue
|
||||
was full.
|
||||
*/
|
||||
bool IRAM_ATTR push();
|
||||
|
||||
/*!
|
||||
@brief Move the rvalue parameter into the queue.
|
||||
@return true if the queue accepted the value, false if the queue
|
||||
was full.
|
||||
*/
|
||||
bool IRAM_ATTR push(T&& val);
|
||||
|
||||
/*!
|
||||
@brief Push a copy of the parameter into the queue.
|
||||
@return true if the queue accepted the value, false if the queue
|
||||
was full.
|
||||
*/
|
||||
bool IRAM_ATTR push(const T& val)
|
||||
{
|
||||
return push(T(val));
|
||||
}
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
/*!
|
||||
@brief Push copies of multiple elements from a buffer into the queue,
|
||||
in order, beginning at buffer's head.
|
||||
@return The number of elements actually copied into the queue, counted
|
||||
from the buffer head.
|
||||
*/
|
||||
size_t push_n(const T* buffer, size_t size);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Pop the next available element from the queue.
|
||||
@return An rvalue copy of the popped element, or a default
|
||||
value of type T if the queue is empty.
|
||||
*/
|
||||
T pop();
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
/*!
|
||||
@brief Pop multiple elements in ordered sequence from the queue to a buffer.
|
||||
If buffer is nullptr, simply discards up to size elements from the queue.
|
||||
@return The number of elements actually popped from the queue to
|
||||
buffer.
|
||||
*/
|
||||
size_t pop_n(T* buffer, size_t size);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Iterate over and remove each available element from queue,
|
||||
calling back fun with an rvalue reference of every single element.
|
||||
*/
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
void for_each(const Delegate<void(T&&), ForEachArg>& fun);
|
||||
#else
|
||||
void for_each(Delegate<void(T&&), ForEachArg> fun);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief In reverse order, iterate over, pop and optionally requeue each available element from the queue,
|
||||
calling back fun with a reference of every single element.
|
||||
Requeuing is dependent on the return boolean of the callback function. If it
|
||||
returns true, the requeue occurs.
|
||||
*/
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
bool for_each_rev_requeue(const Delegate<bool(T&), ForEachArg>& fun);
|
||||
#else
|
||||
bool for_each_rev_requeue(Delegate<bool(T&), ForEachArg> fun);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
const T defaultValue = {};
|
||||
unsigned m_bufSize;
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
std::unique_ptr<T[]> m_buffer;
|
||||
#else
|
||||
std::unique_ptr<T> m_buffer;
|
||||
#endif
|
||||
std::atomic<unsigned> m_inPos;
|
||||
std::atomic<unsigned> m_outPos;
|
||||
};
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
bool circular_queue<T, ForEachArg>::capacity(const size_t cap)
|
||||
{
|
||||
if (cap + 1 == m_bufSize) return true;
|
||||
else if (available() > cap) return false;
|
||||
std::unique_ptr<T[] > buffer(new T[cap + 1]);
|
||||
const auto available = pop_n(buffer, cap);
|
||||
m_buffer.reset(buffer);
|
||||
m_bufSize = cap + 1;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
m_inPos.store(available, std::memory_order_relaxed);
|
||||
m_outPos.store(0, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
bool IRAM_ATTR circular_queue<T, ForEachArg>::push()
|
||||
{
|
||||
const auto inPos = m_inPos.load(std::memory_order_acquire);
|
||||
const unsigned next = (inPos + 1) % m_bufSize;
|
||||
if (next == m_outPos.load(std::memory_order_relaxed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
m_inPos.store(next, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
bool IRAM_ATTR circular_queue<T, ForEachArg>::push(T&& val)
|
||||
{
|
||||
const auto inPos = m_inPos.load(std::memory_order_acquire);
|
||||
const unsigned next = (inPos + 1) % m_bufSize;
|
||||
if (next == m_outPos.load(std::memory_order_relaxed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
m_buffer[inPos] = std::move(val);
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
m_inPos.store(next, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
template< typename T, typename ForEachArg >
|
||||
size_t circular_queue<T, ForEachArg>::push_n(const T* buffer, size_t size)
|
||||
{
|
||||
const auto inPos = m_inPos.load(std::memory_order_acquire);
|
||||
const auto outPos = m_outPos.load(std::memory_order_relaxed);
|
||||
|
||||
size_t blockSize = (outPos > inPos) ? outPos - 1 - inPos : (outPos == 0) ? m_bufSize - 1 - inPos : m_bufSize - inPos;
|
||||
blockSize = min(size, blockSize);
|
||||
if (!blockSize) return 0;
|
||||
int next = (inPos + blockSize) % m_bufSize;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
auto dest = m_buffer.get() + inPos;
|
||||
std::copy_n(std::make_move_iterator(buffer), blockSize, dest);
|
||||
size = min(size - blockSize, outPos > 1 ? static_cast<size_t>(outPos - next - 1) : 0);
|
||||
next += size;
|
||||
dest = m_buffer.get();
|
||||
std::copy_n(std::make_move_iterator(buffer + blockSize), size, dest);
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
m_inPos.store(next, std::memory_order_release);
|
||||
return blockSize + size;
|
||||
}
|
||||
#endif
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
T circular_queue<T, ForEachArg>::pop()
|
||||
{
|
||||
const auto outPos = m_outPos.load(std::memory_order_acquire);
|
||||
if (m_inPos.load(std::memory_order_relaxed) == outPos) return defaultValue;
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
auto val = std::move(m_buffer[outPos]);
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
m_outPos.store((outPos + 1) % m_bufSize, std::memory_order_release);
|
||||
return val;
|
||||
}
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
template< typename T, typename ForEachArg >
|
||||
size_t circular_queue<T, ForEachArg>::pop_n(T* buffer, size_t size) {
|
||||
size_t avail = size = min(size, available());
|
||||
if (!avail) return 0;
|
||||
const auto outPos = m_outPos.load(std::memory_order_acquire);
|
||||
size_t n = min(avail, static_cast<size_t>(m_bufSize - outPos));
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
if (buffer) {
|
||||
buffer = std::copy_n(std::make_move_iterator(m_buffer.get() + outPos), n, buffer);
|
||||
avail -= n;
|
||||
std::copy_n(std::make_move_iterator(m_buffer.get()), avail, buffer);
|
||||
}
|
||||
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
m_outPos.store((outPos + size) % m_bufSize, std::memory_order_release);
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
void circular_queue<T, ForEachArg>::for_each(const Delegate<void(T&&), ForEachArg>& fun)
|
||||
#else
|
||||
void circular_queue<T, ForEachArg>::for_each(Delegate<void(T&&), ForEachArg> fun)
|
||||
#endif
|
||||
{
|
||||
auto outPos = m_outPos.load(std::memory_order_acquire);
|
||||
const auto inPos = m_inPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
while (outPos != inPos)
|
||||
{
|
||||
fun(std::move(m_buffer[outPos]));
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
outPos = (outPos + 1) % m_bufSize;
|
||||
m_outPos.store(outPos, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
#if defined(ESP8266) || defined(ESP32) || !defined(ARDUINO)
|
||||
bool circular_queue<T, ForEachArg>::for_each_rev_requeue(const Delegate<bool(T&), ForEachArg>& fun)
|
||||
#else
|
||||
bool circular_queue<T, ForEachArg>::for_each_rev_requeue(Delegate<bool(T&), ForEachArg> fun)
|
||||
#endif
|
||||
{
|
||||
auto inPos0 = circular_queue<T, ForEachArg>::m_inPos.load(std::memory_order_acquire);
|
||||
auto outPos = circular_queue<T, ForEachArg>::m_outPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
if (outPos == inPos0) return false;
|
||||
auto pos = inPos0;
|
||||
auto outPos1 = inPos0;
|
||||
const auto posDecr = circular_queue<T, ForEachArg>::m_bufSize - 1;
|
||||
do {
|
||||
pos = (pos + posDecr) % circular_queue<T, ForEachArg>::m_bufSize;
|
||||
T&& val = std::move(circular_queue<T, ForEachArg>::m_buffer[pos]);
|
||||
if (fun(val))
|
||||
{
|
||||
outPos1 = (outPos1 + posDecr) % circular_queue<T, ForEachArg>::m_bufSize;
|
||||
if (outPos1 != pos) circular_queue<T, ForEachArg>::m_buffer[outPos1] = std::move(val);
|
||||
}
|
||||
} while (pos != outPos);
|
||||
circular_queue<T, ForEachArg>::m_outPos.store(outPos1, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // __circular_queue_h
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
circular_queue_mp.h - Implementation of a lock-free circular queue for EspSoftwareSerial.
|
||||
Copyright (c) 2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __circular_queue_mp_h
|
||||
#define __circular_queue_mp_h
|
||||
|
||||
#include "circular_queue.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
#include "interrupts.h"
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@brief Instance class for a multi-producer, single-consumer circular queue / ring buffer (FIFO).
|
||||
This implementation is lock-free between producers and consumer for the available(), peek(),
|
||||
pop(), and push() type functions, but is guarded to safely allow only a single producer
|
||||
at any instant.
|
||||
*/
|
||||
template< typename T, typename ForEachArg = void >
|
||||
class circular_queue_mp : protected circular_queue<T, ForEachArg>
|
||||
{
|
||||
public:
|
||||
circular_queue_mp() = default;
|
||||
circular_queue_mp(const size_t capacity) : circular_queue<T, ForEachArg>(capacity)
|
||||
{}
|
||||
circular_queue_mp(circular_queue<T, ForEachArg>&& cq) : circular_queue<T, ForEachArg>(std::move(cq))
|
||||
{}
|
||||
using circular_queue<T, ForEachArg>::operator=;
|
||||
using circular_queue<T, ForEachArg>::capacity;
|
||||
using circular_queue<T, ForEachArg>::flush;
|
||||
using circular_queue<T, ForEachArg>::available;
|
||||
using circular_queue<T, ForEachArg>::available_for_push;
|
||||
using circular_queue<T, ForEachArg>::peek;
|
||||
using circular_queue<T, ForEachArg>::pop;
|
||||
using circular_queue<T, ForEachArg>::pop_n;
|
||||
using circular_queue<T, ForEachArg>::for_each;
|
||||
using circular_queue<T, ForEachArg>::for_each_rev_requeue;
|
||||
|
||||
/*!
|
||||
@brief Resize the queue. The available elements in the queue are preserved.
|
||||
This is not lock-free, but safe, concurrent producer or consumer access
|
||||
is guarded.
|
||||
@return True if the new capacity could accommodate the present elements in
|
||||
the queue, otherwise nothing is done and false is returned.
|
||||
*/
|
||||
bool capacity(const size_t cap)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
return circular_queue<T, ForEachArg>::capacity(cap);
|
||||
}
|
||||
|
||||
bool IRAM_ATTR push() = delete;
|
||||
|
||||
/*!
|
||||
@brief Move the rvalue parameter into the queue, guarded
|
||||
for multiple concurrent producers.
|
||||
@return true if the queue accepted the value, false if the queue
|
||||
was full.
|
||||
*/
|
||||
bool IRAM_ATTR push(T&& val)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
return circular_queue<T, ForEachArg>::push(std::move(val));
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Push a copy of the parameter into the queue, guarded
|
||||
for multiple concurrent producers.
|
||||
@return true if the queue accepted the value, false if the queue
|
||||
was full.
|
||||
*/
|
||||
bool IRAM_ATTR push(const T& val)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
return circular_queue<T, ForEachArg>::push(val);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Push copies of multiple elements from a buffer into the queue,
|
||||
in order, beginning at buffer's head. This is guarded for
|
||||
multiple producers, push_n() is atomic.
|
||||
@return The number of elements actually copied into the queue, counted
|
||||
from the buffer head.
|
||||
*/
|
||||
size_t push_n(const T* buffer, size_t size)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
return circular_queue<T, ForEachArg>::push_n(buffer, size);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Pops the next available element from the queue, requeues
|
||||
it immediately.
|
||||
@return A reference to the just requeued element, or the default
|
||||
value of type T if the queue is empty.
|
||||
*/
|
||||
T& pop_requeue();
|
||||
|
||||
/*!
|
||||
@brief Iterate over, pop and optionally requeue each available element from the queue,
|
||||
calling back fun with a reference of every single element.
|
||||
Requeuing is dependent on the return boolean of the callback function. If it
|
||||
returns true, the requeue occurs.
|
||||
*/
|
||||
bool for_each_requeue(const Delegate<bool(T&), ForEachArg>& fun);
|
||||
|
||||
#ifndef ESP8266
|
||||
protected:
|
||||
std::mutex m_pushMtx;
|
||||
#endif
|
||||
};
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
T& circular_queue_mp<T>::pop_requeue()
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
const auto outPos = circular_queue<T, ForEachArg>::m_outPos.load(std::memory_order_acquire);
|
||||
const auto inPos = circular_queue<T, ForEachArg>::m_inPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
if (inPos == outPos) return circular_queue<T, ForEachArg>::defaultValue;
|
||||
T& val = circular_queue<T, ForEachArg>::m_buffer[inPos] = std::move(circular_queue<T, ForEachArg>::m_buffer[outPos]);
|
||||
const auto bufSize = circular_queue<T, ForEachArg>::m_bufSize;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
circular_queue<T, ForEachArg>::m_outPos.store((outPos + 1) % bufSize, std::memory_order_relaxed);
|
||||
circular_queue<T, ForEachArg>::m_inPos.store((inPos + 1) % bufSize, std::memory_order_release);
|
||||
return val;
|
||||
}
|
||||
|
||||
template< typename T, typename ForEachArg >
|
||||
bool circular_queue_mp<T>::for_each_requeue(const Delegate<bool(T&), ForEachArg>& fun)
|
||||
{
|
||||
auto inPos0 = circular_queue<T, ForEachArg>::m_inPos.load(std::memory_order_acquire);
|
||||
auto outPos = circular_queue<T, ForEachArg>::m_outPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
if (outPos == inPos0) return false;
|
||||
do {
|
||||
T&& val = std::move(circular_queue<T, ForEachArg>::m_buffer[outPos]);
|
||||
if (fun(val))
|
||||
{
|
||||
#ifdef ESP8266
|
||||
esp8266::InterruptLock lock;
|
||||
#else
|
||||
std::lock_guard<std::mutex> lock(m_pushMtx);
|
||||
#endif
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
auto inPos = circular_queue<T, ForEachArg>::m_inPos.load(std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
circular_queue<T, ForEachArg>::m_buffer[inPos] = std::move(val);
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
circular_queue<T, ForEachArg>::m_inPos.store((inPos + 1) % circular_queue<T, ForEachArg>::m_bufSize, std::memory_order_release);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
outPos = (outPos + 1) % circular_queue<T, ForEachArg>::m_bufSize;
|
||||
circular_queue<T, ForEachArg>::m_outPos.store(outPos, std::memory_order_release);
|
||||
} while (outPos != inPos0);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // __circular_queue_mp_h
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
ghostl.h - Implementation of a bare-bones, mostly no-op, C++ STL shell
|
||||
that allows building some Arduino ESP8266/ESP32
|
||||
libraries on Aruduino AVR.
|
||||
Copyright (c) 2019 Dirk O. Kaar. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __ghostl_h
|
||||
#define __ghostl_h
|
||||
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
#if !defined(ARDUINO_ARCH_SAMD)
|
||||
typedef enum memory_order {
|
||||
memory_order_relaxed,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
memory_order_seq_cst
|
||||
} memory_order;
|
||||
template< typename T > class atomic {
|
||||
private:
|
||||
T value;
|
||||
public:
|
||||
atomic() {}
|
||||
atomic(T desired) { value = desired; }
|
||||
void store(T desired, std::memory_order = std::memory_order_seq_cst) volatile noexcept { value = desired; }
|
||||
T load(std::memory_order = std::memory_order_seq_cst) const volatile noexcept { return value; }
|
||||
};
|
||||
inline void atomic_thread_fence(std::memory_order order) noexcept {}
|
||||
template< typename T > T&& move(T& t) noexcept { return static_cast<T&&>(t); }
|
||||
#endif
|
||||
|
||||
template< typename T, unsigned long N > struct array
|
||||
{
|
||||
T _M_elems[N];
|
||||
decltype(sizeof(0)) size() const { return N; }
|
||||
T& operator[](decltype(sizeof(0)) i) { return _M_elems[i]; }
|
||||
const T& operator[](decltype(sizeof(0)) i) const { return _M_elems[i]; }
|
||||
};
|
||||
|
||||
template< typename T > class unique_ptr
|
||||
{
|
||||
public:
|
||||
using pointer = T*;
|
||||
unique_ptr() noexcept : ptr(nullptr) {}
|
||||
unique_ptr(pointer p) : ptr(p) {}
|
||||
pointer operator->() const noexcept { return ptr; }
|
||||
T& operator[](decltype(sizeof(0)) i) const { return ptr[i]; }
|
||||
void reset(pointer p = pointer()) noexcept
|
||||
{
|
||||
delete ptr;
|
||||
ptr = p;
|
||||
}
|
||||
T& operator*() const { return *ptr; }
|
||||
private:
|
||||
pointer ptr;
|
||||
};
|
||||
|
||||
template< typename T > using function = T*;
|
||||
using nullptr_t = decltype(nullptr);
|
||||
|
||||
template<typename T>
|
||||
struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T&& forward(typename identity<T>::type& t) noexcept
|
||||
{
|
||||
return static_cast<typename identity<T>::type&&>(t);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __ghostl_h
|
@ -1,191 +0,0 @@
|
||||
// SDS011 dust sensor PM2.5 and PM10
|
||||
// ---------------------
|
||||
//
|
||||
// By R. Zschiegner (rz@madavi.de)
|
||||
// April 2016
|
||||
//
|
||||
// Documentation:
|
||||
// - The iNovaFitness SDS011 datasheet
|
||||
//
|
||||
// modified by AQ - 2018-11-18
|
||||
//
|
||||
|
||||
#include "SDS011.h"
|
||||
|
||||
static const byte SDS_SLEEP[] = {
|
||||
0xAA, // head
|
||||
0xB4, // command id
|
||||
0x06, // data byte 1
|
||||
0x01, // data byte 2 (set mode)
|
||||
0x00, // data byte 3 (sleep)
|
||||
0x00, // data byte 4
|
||||
0x00, // data byte 5
|
||||
0x00, // data byte 6
|
||||
0x00, // data byte 7
|
||||
0x00, // data byte 8
|
||||
0x00, // data byte 9
|
||||
0x00, // data byte 10
|
||||
0x00, // data byte 11
|
||||
0x00, // data byte 12
|
||||
0x00, // data byte 13
|
||||
0xFF, // data byte 14 (device id byte 1)
|
||||
0xFF, // data byte 15 (device id byte 2)
|
||||
0x05, // checksum
|
||||
0xAB // tail
|
||||
};
|
||||
|
||||
static const byte SDS_START[] = {
|
||||
0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB};
|
||||
|
||||
static const byte SDS_CONT_MODE[] = {
|
||||
0xAA, 0xB4, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x07, 0xAB};
|
||||
|
||||
static const byte SDS_VERSION[] = {
|
||||
0xAA, 0xB4, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB};
|
||||
|
||||
const uint8_t SDS_cmd_len = 19;
|
||||
|
||||
SDS011::SDS011(void) {
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SDS011:read
|
||||
// --------------------------------------------------------
|
||||
int SDS011::read(float *p25, float *p10) {
|
||||
byte buffer;
|
||||
int value;
|
||||
int len = 0;
|
||||
int pm10_serial = 0;
|
||||
int pm25_serial = 0;
|
||||
int checksum_is;
|
||||
int checksum_ok = 0;
|
||||
int error = 1;
|
||||
|
||||
while ((sds_data->available() > 0) && (sds_data->available() >= (10-len))) {
|
||||
buffer = sds_data->read();
|
||||
value = int(buffer);
|
||||
switch (len) {
|
||||
case (0): if (value != 170) { len = -1; }; break;
|
||||
case (1): if (value != 192) { len = -1; }; break;
|
||||
case (2): pm25_serial = value; checksum_is = value; break;
|
||||
case (3): pm25_serial += (value << 8); checksum_is += value; break;
|
||||
case (4): pm10_serial = value; checksum_is += value; break;
|
||||
case (5): pm10_serial += (value << 8); checksum_is += value; break;
|
||||
case (6): checksum_is += value; break;
|
||||
case (7): checksum_is += value; break;
|
||||
case (8): if (value == (checksum_is % 256)) { checksum_ok = 1; } else { len = -1; }; break;
|
||||
case (9): if (value != 171) { len = -1; }; break;
|
||||
}
|
||||
len++;
|
||||
if (len == 10 && checksum_ok == 1) {
|
||||
*p10 = (float)pm10_serial/10.0;
|
||||
*p25 = (float)pm25_serial/10.0;
|
||||
len = 0; checksum_ok = 0; pm10_serial = 0.0; pm25_serial = 0.0; checksum_is = 0;
|
||||
error = 0;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SDS011:sleep
|
||||
// --------------------------------------------------------
|
||||
void SDS011::sleep() {
|
||||
SDS_cmd(SDS_STOP_CMD);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SDS011:wakeup
|
||||
// --------------------------------------------------------
|
||||
void SDS011::wakeup() {
|
||||
SDS_cmd(SDS_START_CMD);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SDS011:continous mode
|
||||
// --------------------------------------------------------
|
||||
void SDS011::contmode(int noOfMinutes)
|
||||
{
|
||||
byte buffer[SDS_cmd_len];
|
||||
memcpy(buffer, SDS_CONT_MODE, SDS_cmd_len);
|
||||
buffer[4] = (byte) noOfMinutes;
|
||||
buffer[17] = calcChecksum( buffer );
|
||||
for (uint8_t i = 0; i < SDS_cmd_len; i++) {
|
||||
sds_data->write(buffer[i]);
|
||||
}
|
||||
sds_data->flush();
|
||||
while (sds_data->available() > 0) {
|
||||
sds_data->read();
|
||||
}
|
||||
// SDS_cmd(SDS_CONTINUOUS_MODE_CMD);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* send SDS011 command (start, stop, continuous mode, version *
|
||||
*****************************************************************/
|
||||
void SDS011::SDS_cmd(const uint8_t cmd)
|
||||
{
|
||||
byte buf[SDS_cmd_len];
|
||||
switch (cmd) {
|
||||
case SDS_START_CMD:
|
||||
memcpy(buf, SDS_START, SDS_cmd_len);
|
||||
break;
|
||||
case SDS_STOP_CMD:
|
||||
memcpy(buf, SDS_SLEEP, SDS_cmd_len);
|
||||
break;
|
||||
case SDS_CONTINUOUS_MODE_CMD:
|
||||
memcpy(buf, SDS_CONT_MODE, SDS_cmd_len);
|
||||
break;
|
||||
case SDS_VERSION_DATE_CMD:
|
||||
memcpy(buf, SDS_VERSION, SDS_cmd_len);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
for (uint8_t i = 0; i < SDS_cmd_len; i++) {
|
||||
sds_data->write(buf[i]);
|
||||
}
|
||||
sds_data->flush();
|
||||
while (sds_data->available() > 0) {
|
||||
sds_data->read();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// SDS011: calculate checksum
|
||||
// --------------------------------------------------------
|
||||
uint8_t SDS011::calcChecksum( byte *buffer )
|
||||
{
|
||||
uint8_t value = 0;
|
||||
|
||||
for (uint8_t i = 2; i < 17; i++ )
|
||||
{
|
||||
value += buffer[i];
|
||||
value &= 0xff;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void SDS011::begin(uint8_t pin_rx, uint8_t pin_tx) {
|
||||
_pin_rx = pin_rx;
|
||||
_pin_tx = pin_tx;
|
||||
|
||||
SoftwareSerial *softSerial = new SoftwareSerial(_pin_rx, _pin_tx);
|
||||
softSerial->begin(9600);
|
||||
|
||||
sds_data = softSerial;
|
||||
}
|
||||
|
||||
void SDS011::begin(HardwareSerial* serial) {
|
||||
Serial.println("SDS011::begin");
|
||||
// serial->begin(9600); // why do I have to remove this line?
|
||||
sds_data = serial;
|
||||
}
|
||||
|
||||
void SDS011::begin(SoftwareSerial* serial) {
|
||||
serial->begin(9600);
|
||||
sds_data = serial;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// SDS011 dust sensor PM2.5 and PM10
|
||||
// ---------------------------------
|
||||
//
|
||||
// By R. Zschiegner (rz@madavi.de)
|
||||
// April 2016
|
||||
//
|
||||
// Documentation:
|
||||
// - The iNovaFitness SDS011 datasheet
|
||||
//
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
// Definition SDS011 sensor 'commands'
|
||||
#define SDS_START_CMD 1
|
||||
#define SDS_STOP_CMD 2
|
||||
#define SDS_CONTINUOUS_MODE_CMD 3
|
||||
#define SDS_VERSION_DATE_CMD 4
|
||||
|
||||
class SDS011 {
|
||||
public:
|
||||
SDS011(void);
|
||||
void begin(uint8_t pin_rx, uint8_t pin_tx);
|
||||
void begin(HardwareSerial* serial);
|
||||
void begin(SoftwareSerial* serial);
|
||||
int read(float *p25, float *p10);
|
||||
void sleep();
|
||||
void wakeup();
|
||||
void contmode( int );
|
||||
private:
|
||||
void SDS_cmd(const uint8_t);
|
||||
uint8_t calcChecksum( byte *);
|
||||
uint8_t _pin_rx, _pin_tx;
|
||||
Stream *sds_data;
|
||||
};
|
@ -48,7 +48,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
|
||||
release_version = 1.9.90
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 5
|
||||
debug_level = 2
|
||||
extra_scripts = pre:build.py
|
||||
otakeyfile = ota.conf
|
||||
lorakeyfile = loraconf.h
|
||||
|
@ -180,7 +180,7 @@ void bme_storedata(bmeStatus_t *bme_store) {
|
||||
iaqSensor.humidity; // humidity in % relative humidity x1000
|
||||
bme_store->pressure = // pressure in Pascal
|
||||
(iaqSensor.pressure / 100.0); // conversion Pa -> hPa
|
||||
bme_store->iaq = iaqSensor.iaqEstimate;
|
||||
bme_store->iaq = iaqSensor.iaq;
|
||||
bme_store->iaq_accuracy = iaqSensor.iaqAccuracy;
|
||||
bme_store->gas = iaqSensor.gasResistance; // gas resistance in ohms
|
||||
updateState();
|
||||
|
@ -68,19 +68,11 @@ void init_display(bool verbose) {
|
||||
ESP_LOGV(TAG, "[%0.3f] i2c mutex lock failed", millis() / 1000.0);
|
||||
else {
|
||||
|
||||
// is we have display RST line we toggle it to re-initialize display
|
||||
#ifdef MY_OLED_RST
|
||||
pinMode(MY_OLED_RST, OUTPUT);
|
||||
digitalWrite(MY_OLED_RST, 0); // initialization of SSD1306 chip is executed
|
||||
delay(1); // keep RES low for at least 3us according to SSD1306 datasheet
|
||||
digitalWrite(MY_OLED_RST, 1); // normal operation
|
||||
#endif
|
||||
|
||||
// init display
|
||||
#ifndef DISPLAY_FLIP
|
||||
oledInit(OLED_128x64, false, false, -1, -1, 400000L);
|
||||
oledInit(OLED_128x64, false, false, -1, -1, MY_OLED_RST, 400000L);
|
||||
#else
|
||||
oledInit(OLED_128x64, true, false, -1, -1, 400000L);
|
||||
oledInit(OLED_128x64, true, false, -1, -1, MY_OLED_RST, 400000L);
|
||||
#endif
|
||||
|
||||
// set display buffer
|
||||
@ -151,9 +143,11 @@ void init_display(bool verbose) {
|
||||
|
||||
void refreshTheDisplay(bool nextPage) {
|
||||
|
||||
static uint8_t DisplayPage = 0;
|
||||
#ifndef HAS_BUTTON
|
||||
static uint32_t framecounter = 0;
|
||||
#endif
|
||||
|
||||
// update histogram if we have a display
|
||||
// update histogram
|
||||
oledPlotCurve(macs.size(), false);
|
||||
|
||||
// if display is switched off we don't refresh it to relax cpu
|
||||
@ -173,12 +167,15 @@ void refreshTheDisplay(bool nextPage) {
|
||||
oledPower(cfg.screenon);
|
||||
}
|
||||
|
||||
if (nextPage) {
|
||||
DisplayPage = (DisplayPage >= DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1);
|
||||
oledFill(0, 1);
|
||||
#ifndef HAS_BUTTON
|
||||
// auto flip page if we are in unattended mode
|
||||
if ((++framecounter) > (DISPLAYCYCLE * 1000 / DISPLAYREFRESH_MS)) {
|
||||
framecounter = 0;
|
||||
nextPage = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
draw_page(t, DisplayPage);
|
||||
draw_page(t, nextPage);
|
||||
oledDumpBuffer(displaybuf);
|
||||
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
@ -198,8 +195,12 @@ void shutdown_display(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void draw_page(time_t t, uint8_t page) {
|
||||
void draw_page(time_t t, bool nextpage) {
|
||||
|
||||
// write display content to display buffer
|
||||
// nextpage = true -> flip 1 page
|
||||
|
||||
static uint8_t DisplayPage = 0;
|
||||
char timeState;
|
||||
#if (HAS_GPS)
|
||||
static bool wasnofix = true;
|
||||
@ -209,7 +210,14 @@ void draw_page(time_t t, uint8_t page) {
|
||||
dp_printf(0, 0, FONT_STRETCHED, 0, "PAX:%-4d",
|
||||
macs.size()); // display number of unique macs total Wifi + BLE
|
||||
|
||||
switch (page % DISPLAY_PAGES) {
|
||||
start:
|
||||
|
||||
if (nextpage) {
|
||||
DisplayPage = (DisplayPage >= DISPLAY_PAGES - 1) ? 0 : (DisplayPage + 1);
|
||||
oledFill(0, 1);
|
||||
}
|
||||
|
||||
switch (DisplayPage) {
|
||||
|
||||
// page 0: parameters overview
|
||||
// page 1: pax graph
|
||||
@ -293,8 +301,7 @@ void draw_page(time_t t, uint8_t page) {
|
||||
// LORA datarate, display inverse if ADR disabled
|
||||
dp_printf(102, 7, FONT_SMALL, !cfg.adrmode, "%-4s",
|
||||
getSfName(updr2rps(LMIC.datarate)));
|
||||
#endif // HAS_LORA
|
||||
|
||||
#endif // HAS_LORA
|
||||
break; // page0
|
||||
|
||||
// page 1: pax graph
|
||||
@ -323,16 +330,13 @@ void draw_page(time_t t, uint8_t page) {
|
||||
dp_printf(16, 5, FONT_STRETCHED, 1, "No fix");
|
||||
wasnofix = true;
|
||||
}
|
||||
|
||||
#else
|
||||
dp_printf(16, 5, FONT_STRETCHED, 1, "No GPS");
|
||||
#endif
|
||||
|
||||
break; // page2
|
||||
#else
|
||||
DisplayPage++; // next page
|
||||
#endif
|
||||
|
||||
// page 3: BME280/680
|
||||
case 3:
|
||||
|
||||
#if (HAS_BME)
|
||||
// line 2-3: Temp
|
||||
dp_printf(0, 2, FONT_STRETCHED, 0, "TMP:%-2.1f", bme_status.temperature);
|
||||
@ -343,32 +347,32 @@ void draw_page(time_t t, uint8_t page) {
|
||||
#ifdef HAS_BME680
|
||||
// line 6-7: IAQ
|
||||
dp_printf(0, 6, FONT_STRETCHED, 0, "IAQ:%-3.0f", bme_status.iaq);
|
||||
#else // is BME280 or BMP180
|
||||
#else // is BME280 or BMP180
|
||||
// line 6-7: Pre
|
||||
dp_printf(0, 6, FONT_STRETCHED, 0, "PRE:%-2.1f", bme_status.pressure);
|
||||
#endif // HAS_BME
|
||||
|
||||
#endif // HAS_BME680
|
||||
break; // page 3
|
||||
#else
|
||||
dp_printf(16, 5, FONT_STRETCHED, 1, "No BME");
|
||||
#endif
|
||||
|
||||
break; // page3
|
||||
DisplayPage++; // next page
|
||||
#endif // HAS_BME
|
||||
|
||||
// page 4: time
|
||||
case 4:
|
||||
|
||||
dp_printf(0, 4, FONT_LARGE, 0, "%02d:%02d:%02d", hour(t), minute(t),
|
||||
second(t));
|
||||
break;
|
||||
|
||||
// page 5: blank screen
|
||||
case 5:
|
||||
|
||||
#ifdef HAS_BUTTON
|
||||
oledFill(0, 1);
|
||||
break;
|
||||
#else // don't show blank page if we are unattended
|
||||
DisplayPage++; // next page
|
||||
#endif
|
||||
|
||||
default:
|
||||
break; // default
|
||||
goto start; // start over
|
||||
|
||||
} // switch
|
||||
|
||||
|
@ -10,10 +10,6 @@
|
||||
// Hardware related definitions for generic ESP32 boards
|
||||
// generic.h is kitchensink with all available options
|
||||
|
||||
// SDS011 dust sensor settings
|
||||
// #define HAS_SDS011 1 // use SDS011
|
||||
// #define SDS011_SERIAL 9600, SERIAL_8N1, GPIO_NUM_19, GPIO_NUM_23 // SDS011 RX, TX
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa
|
||||
#define HAS_SPI 1 // comment out if device shall not send data via SPI
|
||||
// pin definitions for SPI slave interface
|
||||
|
@ -43,7 +43,7 @@
|
||||
#define LORA_IRQ DIO0
|
||||
#define LORA_IO1 DIO1
|
||||
#define LORA_IO2 DIO2
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_SCK GPIO_NUM_5
|
||||
#define LORA_MISO MISO
|
||||
#define LORA_MOSI MOSI
|
||||
#define LORA_RST RST_LoRa
|
||||
|
62
src/hal/m5core.h
Normal file
62
src/hal/m5core.h
Normal file
@ -0,0 +1,62 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board m5stack-core-esp32
|
||||
|
||||
// EXPERIMENTAL VERSION - NOT TESTED ON M5 HARDWARE YET
|
||||
|
||||
#ifndef _M5CORE_H
|
||||
#define _M5CORE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no M5 RA01 LoRa module
|
||||
|
||||
// Pins for LORA chip SPI interface, reset line and interrupt lines
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_CS SS
|
||||
#define LORA_MISO MISO
|
||||
#define LORA_MOSI MOSI
|
||||
#define LORA_RST GPIO_NUM_36
|
||||
#define LORA_IRQ GPIO_NUM_26
|
||||
#define LORA_IO1 GPIO_NUM_34 // must be externally wired on PCB!
|
||||
#define LORA_IO2 LMIC_UNUSED_PIN
|
||||
|
||||
|
||||
// enable only if you want to store a local paxcount table on the device
|
||||
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
|
||||
// Pins for SD-card
|
||||
#define SDCARD_CS GPIO_NUM_4
|
||||
#define SDCARD_MOSI MOSI
|
||||
#define SDCARD_MISO MISO
|
||||
#define SDCARD_SCLK SCK
|
||||
|
||||
// user defined sensors
|
||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
||||
|
||||
#define CFG_sx1276_radio 1 // select LoRa chip
|
||||
#define BOARD_HAS_PSRAM // use if board has external PSRAM
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
//#define HAS_DISPLAY 1
|
||||
//#define DISPLAY_FLIP 1 // use if display is rotated
|
||||
//#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board
|
||||
|
||||
#define HAS_LED NOT_A_PIN // no on board LED (?)
|
||||
#define HAS_BUTTON (39) // on board button A
|
||||
|
||||
// GPS settings
|
||||
#define HAS_GPS 1 // use on board GPS
|
||||
#define GPS_SERIAL 9600, SERIAL_8N1, RXD2, TXD2 // UBlox NEO 6M RX, TX
|
||||
#define GPS_INT GPIO_NUM_35 // 30ns accurary timepulse, to be external wired on pcb: shorten R12!
|
||||
|
||||
// Pins for interface of LC Display
|
||||
#define MY_OLED_CS GPIO_NUM_14
|
||||
#define MY_OLED_DC GPIO_NUM_27
|
||||
#define MY_OLED_CLK GPIO_NUM_18
|
||||
#define MY_OLED_RST GPIO_NUM_33
|
||||
#define MY_OLED_BL GPIO_NUM_32
|
||||
#define MY_OLED_MOSI GPIO_NUM_23
|
||||
#define MY_OLED_MISO GPIO_NUM_19
|
||||
|
||||
#endif
|
64
src/hal/m5fire.h
Normal file
64
src/hal/m5fire.h
Normal file
@ -0,0 +1,64 @@
|
||||
// clang-format off
|
||||
// upload_speed 921600
|
||||
// board m5stack-fire
|
||||
|
||||
// EXPERIMENTAL VERSION - NOT TESTED ON M5 HARDWARE YET
|
||||
|
||||
#ifndef _M5FIRE_H
|
||||
#define _M5FIRE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// #define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no M5 RA01 LoRa module
|
||||
|
||||
// Pins for LORA chip SPI interface, reset line and interrupt lines
|
||||
#define LORA_SCK SCK
|
||||
#define LORA_CS SS
|
||||
#define LORA_MISO MISO
|
||||
#define LORA_MOSI MOSI
|
||||
#define LORA_RST GPIO_NUM_36
|
||||
#define LORA_IRQ GPIO_NUM_26
|
||||
#define LORA_IO1 GPIO_NUM_34 // must be externally wired on PCB!
|
||||
#define LORA_IO2 LMIC_UNUSED_PIN
|
||||
|
||||
|
||||
// enable only if you want to store a local paxcount table on the device
|
||||
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer
|
||||
// Pins for SD-card
|
||||
#define SDCARD_CS GPIO_NUM_4
|
||||
#define SDCARD_MOSI MOSI
|
||||
#define SDCARD_MISO MISO
|
||||
#define SDCARD_SCLK SCK
|
||||
|
||||
// user defined sensors
|
||||
//#define HAS_SENSORS 1 // comment out if device has user defined sensors
|
||||
|
||||
#define CFG_sx1276_radio 1 // select LoRa chip
|
||||
#define BOARD_HAS_PSRAM // use if board has external PSRAM
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
//#define HAS_DISPLAY 1
|
||||
#define HAS_TFT 1
|
||||
//#define DISPLAY_FLIP 1 // use if display is rotated
|
||||
//#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
//#define BAT_VOLTAGE_DIVIDER 2 // voltage divider 100k/100k on board
|
||||
|
||||
#define HAS_LED NOT_A_PIN // no on board LED (?)
|
||||
#define HAS_RGB_LED SmartLed rgb_led(LED_SK6812, 10, GPIO_NUM_15) // LED_SK6812 RGB LED on GPIO15
|
||||
#define HAS_BUTTON (39) // on board button A
|
||||
|
||||
// GPS settings
|
||||
#define HAS_GPS 0 // use on board GPS
|
||||
#define GPS_SERIAL 9600, SERIAL_8N1, RXD2, TXD2 // UBlox NEO 6M RX, TX
|
||||
// #define GPS_INT GPIO_NUM_35 // 30ns accurary timepulse, to be external wired on pcb: shorten R12!
|
||||
|
||||
// Pins for interface of LC Display
|
||||
#define MY_OLED_CS GPIO_NUM_14
|
||||
#define MY_OLED_DC GPIO_NUM_27
|
||||
#define MY_OLED_CLK GPIO_NUM_18
|
||||
#define MY_OLED_RST GPIO_NUM_33
|
||||
#define MY_OLED_BL GPIO_NUM_32
|
||||
#define MY_OLED_MOSI GPIO_NUM_23
|
||||
#define MY_OLED_MISO GPIO_NUM_19
|
||||
|
||||
#endif
|
@ -44,10 +44,11 @@ void start_ota_update() {
|
||||
|
||||
// init display
|
||||
#ifdef HAS_DISPLAY
|
||||
|
||||
#ifndef DISPLAY_FLIP
|
||||
oledInit(OLED_128x64, ANGLE_0, false, -1, -1, 400000L);
|
||||
oledInit(OLED_128x64, false, false, -1, -1, MY_OLED_RST, 400000L);
|
||||
#else
|
||||
oledInit(OLED_128x64, ANGLE_FLIPY, false, -1, -1, 400000L);
|
||||
oledInit(OLED_128x64, true, false, -1, -1, MY_OLED_RST, 400000L);
|
||||
#endif
|
||||
|
||||
// set display buffer
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define RGBLUMINOSITY 30 // RGB LED luminosity [default = 30%]
|
||||
#define DISPLAYREFRESH_MS 40 // OLED refresh cycle in ms [default = 40] -> 1000/40 = 25 frames per second
|
||||
#define DISPLAYCONTRAST 80 // 0 .. 255, OLED display contrast [default = 80]
|
||||
#define DISPLAYCYCLE 3 // Auto page flip delay in sec [default = 2] for devices without button
|
||||
#define HOMECYCLE 30 // house keeping cycle in seconds [default = 30 secs]
|
||||
|
||||
// Settings for BME680 environmental sensor
|
||||
@ -93,7 +94,7 @@
|
||||
#define RCMDPORT 2 // remote commands
|
||||
#define STATUSPORT 2 // remote command results
|
||||
#define CONFIGPORT 3 // config query results
|
||||
#define GPSPORT 4 // gps - set to 1 to send combined GPS+COUNTERPORT payload
|
||||
#define GPSPORT 1 // gps - set to 1 to send combined GPS+COUNTERPORT payload
|
||||
#define BUTTONPORT 5 // button pressed signal
|
||||
#define BEACONPORT 6 // beacon alarms
|
||||
#define BMEPORT 7 // BME680 sensor
|
||||
|
@ -20,10 +20,9 @@ boolean isSDS011Active;
|
||||
// init
|
||||
bool sds011_init() {
|
||||
pm25 = pm10 = 0.0;
|
||||
#if (HAS_SDS011)
|
||||
sdsSensor.begin (&sdsSerial, ESP_PIN_RX, ESP_PIN_TX);
|
||||
delay(100);
|
||||
// sdsSerial.begin(SDS011_SERIAL);
|
||||
//sdsSensor.contmode(0); // for safety: no wakeup/sleep by the sensor
|
||||
#endif
|
||||
sds011_sleep(); // we do sleep/wakup by ourselves
|
||||
return true;
|
||||
}
|
||||
@ -57,3 +56,5 @@ void sds011_wakeup() {
|
||||
isSDS011Active = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAS_SDS
|
Loading…
Reference in New Issue
Block a user