initial
This commit is contained in:
		
							parent
							
								
									7f066f338f
								
							
						
					
					
						commit
						5009ec0563
					
				| @ -3,30 +3,52 @@ | ||||
| 
 | ||||
| #include "globals.h" | ||||
| #include <Wire.h> | ||||
| #include "bsec_integration.h" | ||||
| #include "irqhandler.h" | ||||
| 
 | ||||
| extern const uint8_t bsec_config_iaq[454]; | ||||
| #include "bsec.h" | ||||
| 
 | ||||
| extern bmeStatus_t | ||||
|     bme_status; // Make struct for storing gps data globally available
 | ||||
| extern TaskHandle_t BmeTask; | ||||
| 
 | ||||
| // --- Bosch BSEC library configuration ---
 | ||||
| // 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
 | ||||
| // calibration. Change this const if not applicable for your application (see
 | ||||
| // BME680 datasheet)
 | ||||
| const uint8_t bsec_config_iaq[454] = { | ||||
|     1,   7,   4,   1,   61,  0,   0,   0,   0,   0,   0,   0,   174, 1,   0, | ||||
|     0,   48,  0,   1,   0,   137, 65,  0,   63,  205, 204, 204, 62,  0,   0, | ||||
|     64,  63,  205, 204, 204, 62,  0,   0,   225, 68,  0,   192, 168, 71,  64, | ||||
|     49,  119, 76,  0,   0,   0,   0,   0,   80,  5,   95,  0,   0,   0,   0, | ||||
|     0,   0,   0,   0,   28,  0,   2,   0,   0,   244, 1,   225, 0,   25,  0, | ||||
|     0,   128, 64,  0,   0,   32,  65,  144, 1,   0,   0,   112, 65,  0,   0, | ||||
|     0,   63,  16,  0,   3,   0,   10,  215, 163, 60,  10,  215, 35,  59,  10, | ||||
|     215, 35,  59,  9,   0,   5,   0,   0,   0,   0,   0,   1,   88,  0,   9, | ||||
|     0,   229, 208, 34,  62,  0,   0,   0,   0,   0,   0,   0,   0,   218, 27, | ||||
|     156, 62,  225, 11,  67,  64,  0,   0,   160, 64,  0,   0,   0,   0,   0, | ||||
|     0,   0,   0,   94,  75,  72,  189, 93,  254, 159, 64,  66,  62,  160, 191, | ||||
|     0,   0,   0,   0,   0,   0,   0,   0,   33,  31,  180, 190, 138, 176, 97, | ||||
|     64,  65,  241, 99,  190, 0,   0,   0,   0,   0,   0,   0,   0,   167, 121, | ||||
|     71,  61,  165, 189, 41,  192, 184, 30,  189, 64,  12,  0,   10,  0,   0, | ||||
|     0,   0,   0,   0,   0,   0,   0,   229, 0,   254, 0,   2,   1,   5,   48, | ||||
|     117, 100, 0,   44,  1,   112, 23,  151, 7,   132, 3,   197, 0,   92,  4, | ||||
|     144, 1,   64,  1,   64,  1,   144, 1,   48,  117, 48,  117, 48,  117, 48, | ||||
|     117, 100, 0,   100, 0,   100, 0,   48,  117, 48,  117, 48,  117, 100, 0, | ||||
|     100, 0,   48,  117, 48,  117, 100, 0,   100, 0,   100, 0,   100, 0,   48, | ||||
|     117, 48,  117, 48,  117, 100, 0,   100, 0,   100, 0,   48,  117, 48,  117, | ||||
|     100, 0,   100, 0,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44, | ||||
|     1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1, | ||||
|     44,  1,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8, | ||||
|     7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7, | ||||
|     112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, | ||||
|     23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 220, 5,   220, 5,   220, 5,   255, 255, 255, | ||||
|     255, 255, 255, 220, 5,   220, 5,   255, 255, 255, 255, 255, 255, 255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 255, 255, 255, 44,  1,   0,   0,   0,   0, | ||||
|     239, 79,  0,   0}; | ||||
| 
 | ||||
| int bme_init(); | ||||
| void bme_loop(void *pvParameters); | ||||
| int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, | ||||
|                 uint16_t len); | ||||
| int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, | ||||
|                  uint16_t len); | ||||
| void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, | ||||
|                   float temperature, float humidity, float pressure, | ||||
|                   float raw_temperature, float raw_humidity, float gas, | ||||
|                   bsec_library_return_t bsec_status, float static_iaq, | ||||
|                   float co2_equivalent, float breath_voc_equivalent); | ||||
| uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer); | ||||
| void state_save(const uint8_t *state_buffer, uint32_t length); | ||||
| uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer); | ||||
| void user_delay_ms(uint32_t period); | ||||
| int64_t get_timestamp_us(); | ||||
| int checkIaqSensorStatus(void); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										493
									
								
								lib/Bosch-BSEC/bsec.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										493
									
								
								lib/Bosch-BSEC/bsec.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,493 @@ | ||||
| /**
 | ||||
|  * 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; | ||||
| 			inputs[nInputs].signal = _data.temperature; | ||||
| 			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; | ||||
| 			inputs[nInputs].signal = _data.humidity; | ||||
| 			inputs[nInputs].time_stamp = currTimeNs; | ||||
| 			nInputs++; | ||||
| 		} | ||||
| 		if (bme680Settings.process_data & BSEC_PROCESS_PRESSURE) { | ||||
| 			inputs[nInputs].sensor_id = BSEC_INPUT_PRESSURE; | ||||
| 			inputs[nInputs].signal = _data.pressure; | ||||
| 			inputs[nInputs].time_stamp = currTimeNs; | ||||
| 			nInputs++; | ||||
| 		} | ||||
| 		if (bme680Settings.process_data & BSEC_PROCESS_GAS) { | ||||
| 			inputs[nInputs].sensor_id = BSEC_INPUT_GASRESISTOR; | ||||
| 			inputs[nInputs].signal = _data.gas_resistance; | ||||
| 			inputs[nInputs].time_stamp = currTimeNs; | ||||
| 			nInputs++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (nInputs > 0) { | ||||
| 		nOutputs = BSEC_NUMBER_OUTPUTS; | ||||
| 		bsec_output_t _outputs[BSEC_NUMBER_OUTPUTS]; | ||||
| 
 | ||||
| 		status = bsec_do_steps(inputs, nInputs, _outputs, &nOutputs); | ||||
| 		if (status != BSEC_OK) | ||||
| 			return false; | ||||
| 
 | ||||
| 		zeroOutputs(); | ||||
| 
 | ||||
| 		if (nOutputs > 0) { | ||||
| 			outputTimestamp = _outputs[0].time_stamp / 1000000; // Convert from ns to ms
 | ||||
| 
 | ||||
| 			for (uint8_t i = 0; i < nOutputs; i++) { | ||||
| 				switch (_outputs[i].sensor_id) { | ||||
| 					case BSEC_OUTPUT_IAQ: | ||||
| 						iaqEstimate = _outputs[i].signal; | ||||
| 						iaqAccuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_STATIC_IAQ: | ||||
| 						staticIaq = _outputs[i].signal; | ||||
| 						staticIaqAccuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_CO2_EQUIVALENT: | ||||
| 						co2Equivalent = _outputs[i].signal; | ||||
| 						co2Accuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT: | ||||
| 						breathVocEquivalent = _outputs[i].signal; | ||||
| 						breathVocAccuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_RAW_TEMPERATURE: | ||||
| 						rawTemperature = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_RAW_PRESSURE: | ||||
| 						pressure = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_RAW_HUMIDITY: | ||||
| 						rawHumidity = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_RAW_GAS: | ||||
| 						gasResistance = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_STABILIZATION_STATUS: | ||||
| 						stabStatus = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_RUN_IN_STATUS: | ||||
| 						runInStatus = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE: | ||||
| 						temperature = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY: | ||||
| 						humidity = _outputs[i].signal; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_COMPENSATED_GAS: | ||||
| 						compGasValue = _outputs[i].signal; | ||||
| 						compGasAccuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					case BSEC_OUTPUT_GAS_PERCENTAGE: | ||||
| 						gasPercentage = _outputs[i].signal; | ||||
| 						gasPercentageAcccuracy = _outputs[i].accuracy; | ||||
| 						break; | ||||
| 					default: | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Set the BME680 sensor's configuration | ||||
|  */ | ||||
| int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) | ||||
| { | ||||
| 	_bme680.gas_sett.run_gas = bme680Settings.run_gas; | ||||
| 	_bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling; | ||||
| 	_bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling; | ||||
| 	_bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling; | ||||
| 	_bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature; | ||||
| 	_bme680.gas_sett.heatr_dur = bme680Settings.heating_duration; | ||||
| 	uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | ||||
| 	        | BME680_GAS_SENSOR_SEL; | ||||
| 	return bme680_set_sensor_settings(desired_settings, &_bme680); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Function to zero the outputs | ||||
|  */ | ||||
| void Bsec::zeroOutputs(void) | ||||
| { | ||||
| 	temperature = 0.0f; | ||||
| 	pressure = 0.0f; | ||||
| 	humidity = 0.0f; | ||||
| 	gasResistance = 0.0f; | ||||
| 	rawTemperature = 0.0f; | ||||
| 	rawHumidity = 0.0f; | ||||
| 	stabStatus = 0.0f; | ||||
| 	runInStatus = 0.0f; | ||||
| 	iaqEstimate = 0.0f; | ||||
| 	iaqAccuracy = 0; | ||||
| 	staticIaq = 0.0f; | ||||
| 	staticIaqAccuracy = 0; | ||||
| 	co2Equivalent = 0.0f; | ||||
| 	co2Accuracy = 0; | ||||
| 	breathVocEquivalent = 0.0f; | ||||
| 	breathVocAccuracy = 0; | ||||
| 	compGasValue = 0.0f; | ||||
| 	compGasAccuracy = 0; | ||||
| 	gasPercentage = 0.0f; | ||||
| 	gasPercentageAcccuracy = 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Function to calculate an int64_t timestamp in milliseconds | ||||
|  */ | ||||
| int64_t Bsec::getTimeMs(void) | ||||
| { | ||||
| 	int64_t timeMs = millis(); | ||||
| 
 | ||||
| 	if (lastTime > timeMs) { // An overflow occured
 | ||||
| 		lastTime = timeMs; | ||||
| 		millisOverflowCounter++; | ||||
| 	} | ||||
| 
 | ||||
| 	return timeMs + (millisOverflowCounter * 0xFFFFFFFF); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  @brief Task that delays for a ms period of time | ||||
|  */ | ||||
| void Bsec::delay_ms(uint32_t period) | ||||
| { | ||||
| 	// Wait for a period amount of ms
 | ||||
| 	// The system may simply idle, sleep or even perform background tasks
 | ||||
| 	delay(period); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  @brief Callback function for reading registers over I2C | ||||
|  */ | ||||
| int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) | ||||
| { | ||||
| 	uint16_t i; | ||||
| 	int8_t rslt = 0; | ||||
| 	if(Bsec::wireObj) { | ||||
| 		Bsec::wireObj->beginTransmission(devId); | ||||
| 		Bsec::wireObj->write(regAddr); | ||||
| 		rslt = Bsec::wireObj->endTransmission(); | ||||
| 		Bsec::wireObj->requestFrom((int) devId, (int) length); | ||||
| 		for (i = 0; (i < length) && Bsec::wireObj->available(); i++) { | ||||
| 			regData[i] = Bsec::wireObj->read(); | ||||
| 		} | ||||
| 	} else { | ||||
| 		rslt = -1; | ||||
| 	} | ||||
| 	return rslt; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Callback function for writing registers over I2C | ||||
|  */ | ||||
| int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) | ||||
| { | ||||
| 	uint16_t i; | ||||
| 	int8_t rslt = 0; | ||||
| 	if(Bsec::wireObj) { | ||||
| 		Bsec::wireObj->beginTransmission(devId); | ||||
| 		Bsec::wireObj->write(regAddr); | ||||
| 		for (i = 0; i < length; i++) { | ||||
| 			Bsec::wireObj->write(regData[i]); | ||||
| 		} | ||||
| 		rslt = Bsec::wireObj->endTransmission(); | ||||
| 	} else { | ||||
| 		rslt = -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return rslt; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Callback function for reading and writing registers over SPI | ||||
|  */ | ||||
| int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) | ||||
| { | ||||
| 	int8_t rslt = 0; | ||||
| 	if(Bsec::spiObj) { | ||||
| 		Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz
 | ||||
| 	 | ||||
| 		digitalWrite(devId, LOW); | ||||
| 
 | ||||
| 		Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return
 | ||||
| 		for (uint16_t i = 0; i < length; i++) | ||||
| 			regData[i] = Bsec::spiObj->transfer(regData[i]); | ||||
| 
 | ||||
| 		digitalWrite(devId, HIGH); | ||||
| 		Bsec::spiObj->endTransaction(); | ||||
| 	} else { | ||||
| 		rslt = -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return rslt;; | ||||
| } | ||||
							
								
								
									
										230
									
								
								lib/Bosch-BSEC/bsec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								lib/Bosch-BSEC/bsec.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,230 @@ | ||||
| /**
 | ||||
|  * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * Redistributions of source code must retain the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * Neither the name of the copyright holder nor the names of the | ||||
|  * contributors may be used to endorse or promote products derived from | ||||
|  * this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||||
|  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
|  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER | ||||
|  * OR CONTRIBUTORS BE LIABLE FOR ANY | ||||
|  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | ||||
|  * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, | ||||
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
|  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||||
|  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||||
|  * ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE | ||||
|  * | ||||
|  * The information provided is believed to be accurate and reliable. | ||||
|  * The copyright holder assumes no responsibility | ||||
|  * for the consequences of use | ||||
|  * of such information nor for any infringement of patents or | ||||
|  * other rights of third parties which may result from its use. | ||||
|  * No license is granted by implication or otherwise under any patent or | ||||
|  * patent rights of the copyright holder. | ||||
|  * | ||||
|  * @file	bsec.h | ||||
|  * @date	31 Jan 2018 | ||||
|  * @version	1.0 | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef BSEC_CLASS_H | ||||
| #define BSEC_CLASS_H | ||||
| 
 | ||||
| /* Includes */ | ||||
| #include "Arduino.h" | ||||
| #include "Wire.h" | ||||
| #include "SPI.h" | ||||
| #include "bsec_datatypes.h" | ||||
| #include "bsec_interface.h" | ||||
| #include "bme680.h" | ||||
| 
 | ||||
| /* BSEC class definition */ | ||||
| class Bsec | ||||
| { | ||||
| public: | ||||
| 	/* Public variables */ | ||||
| 	bsec_version_t version;		// Stores the version of the BSEC algorithm
 | ||||
| 	int64_t nextCall;			// Stores the time when the algorithm has to be called next in ms
 | ||||
| 	int8_t bme680Status;		// Placeholder for the BME680 driver's error codes
 | ||||
| 	bsec_library_return_t status; | ||||
| 	float iaqEstimate, rawTemperature, pressure, rawHumidity, gasResistance, stabStatus, runInStatus, temperature, humidity, | ||||
| 	      staticIaq, co2Equivalent, breathVocEquivalent, compGasValue, gasPercentage; | ||||
| 	uint8_t iaqAccuracy, staticIaqAccuracy, co2Accuracy, breathVocAccuracy, compGasAccuracy, gasPercentageAcccuracy; | ||||
| 	int64_t outputTimestamp;	// Timestamp in ms of the output
 | ||||
| 	static TwoWire *wireObj; | ||||
| 	static SPIClass *spiObj; | ||||
| 
 | ||||
| 	/* Public APIs */ | ||||
| 	/**
 | ||||
| 	 * @brief Constructor | ||||
| 	 */ | ||||
| 	Bsec(); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to initialize the BSEC library and the BME680 sensor | ||||
| 	 * @param devId		: Device identifier parameter for the read/write interface functions | ||||
| 	 * @param intf		: Physical communication interface | ||||
| 	 * @param read		: Pointer to the read function | ||||
| 	 * @param write		: Pointer to the write function | ||||
| 	 * @param idleTask	: Pointer to the idling task | ||||
| 	 */ | ||||
| 	void begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, bme680_com_fptr_t write, bme680_delay_fptr_t idleTask); | ||||
| 	 | ||||
| 	/**
 | ||||
| 	 * @brief Function to initialize the BSEC library and the BME680 sensor | ||||
| 	 * @param i2cAddr	: I2C address | ||||
| 	 * @param i2c		: Pointer to the TwoWire object | ||||
| 	 */ | ||||
| 	void begin(uint8_t i2cAddr, TwoWire &i2c); | ||||
| 	 | ||||
| 	/**
 | ||||
| 	 * @brief Function to initialize the BSEC library and the BME680 sensor | ||||
| 	 * @param chipSelect	: SPI chip select | ||||
| 	 * @param spi			: Pointer to the SPIClass object | ||||
| 	 */ | ||||
| 	void begin(uint8_t chipSelect, SPIClass &spi); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function that sets the desired sensors and the sample rates | ||||
| 	 * @param sensorList	: The list of output sensors | ||||
| 	 * @param nSensors		: Number of outputs requested | ||||
| 	 * @param sampleRate	: The sample rate of requested sensors | ||||
| 	 */ | ||||
| 	void updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate = BSEC_SAMPLE_RATE_ULP); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Callback from the user to trigger reading of data from the BME680, process and store outputs | ||||
| 	 * @return true if there are new outputs. false otherwise | ||||
| 	 */ | ||||
| 	bool run(void); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to get the state of the algorithm to save to non-volatile memory | ||||
| 	 * @param state			: Pointer to a memory location that contains the state | ||||
| 	 */ | ||||
| 	void getState(uint8_t *state); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to set the state of the algorithm from non-volatile memory | ||||
| 	 * @param state			: Pointer to a memory location that contains the state | ||||
| 	 */ | ||||
| 	void setState(uint8_t *state); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to set the configuration of the algorithm from memory | ||||
| 	 * @param state			: Pointer to a memory location that contains the configuration | ||||
| 	 */ | ||||
| 	void setConfig(const uint8_t *config); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to set the temperature offset | ||||
| 	 * @param tempOffset	: Temperature offset in degree Celsius | ||||
| 	 */ | ||||
| 	void setTemperatureOffset(float tempOffset) | ||||
| 	{ | ||||
| 		_tempOffset = tempOffset; | ||||
| 	} | ||||
| 	 | ||||
| 		 | ||||
| 	/**
 | ||||
| 	 * @brief Function to calculate an int64_t timestamp in milliseconds | ||||
| 	 */ | ||||
| 	int64_t getTimeMs(void); | ||||
| 	 | ||||
| 	/**
 | ||||
| 	* @brief Task that delays for a ms period of time | ||||
| 	* @param period	: Period of time in ms | ||||
| 	*/ | ||||
| 	static void delay_ms(uint32_t period); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	* @brief Callback function for reading registers over I2C | ||||
| 	* @param devId		: Library agnostic parameter to identify the device to communicate with | ||||
| 	* @param regAddr	: Register address | ||||
| 	* @param regData	: Pointer to the array containing the data to be read | ||||
| 	* @param length	: Length of the array of data | ||||
| 	* @return	Zero for success, non-zero otherwise | ||||
| 	*/ | ||||
| 	static int8_t i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	* @brief Callback function for writing registers over I2C | ||||
| 	* @param devId		: Library agnostic parameter to identify the device to communicate with | ||||
| 	* @param regAddr	: Register address | ||||
| 	* @param regData	: Pointer to the array containing the data to be written | ||||
| 	* @param length	: Length of the array of data | ||||
| 	* @return	Zero for success, non-zero otherwise | ||||
| 	*/ | ||||
| 	static int8_t i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	* @brief Callback function for reading and writing registers over SPI | ||||
| 	* @param devId		: Library agnostic parameter to identify the device to communicate with | ||||
| 	* @param regAddr	: Register address | ||||
| 	* @param regData	: Pointer to the array containing the data to be read or written | ||||
| 	* @param length	: Length of the array of data | ||||
| 	* @return	Zero for success, non-zero otherwise | ||||
| 	*/ | ||||
| 	static int8_t spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length); | ||||
| 
 | ||||
| private: | ||||
| 	/* Private variables */ | ||||
| 	struct bme680_dev _bme680; | ||||
| 	struct bme680_field_data _data; | ||||
| 	float _tempOffset; | ||||
| 	// Global variables to help create a millisecond timestamp that doesn't overflow every 51 days.
 | ||||
| 	// If it overflows, it will have a negative value. Something that should never happen.
 | ||||
| 	uint32_t millisOverflowCounter; | ||||
| 	uint32_t lastTime; | ||||
| 
 | ||||
| 	/* Private APIs */ | ||||
| 	/**
 | ||||
| 	 * @brief Get the version of the BSEC library | ||||
| 	 */ | ||||
| 	void getVersion(void); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Read data from the BME680 and process it | ||||
| 	 * @param currTimeNs: Current time in ns | ||||
| 	 * @param bme680Settings: BME680 sensor's settings | ||||
| 	 * @return true if there are new outputs. false otherwise | ||||
| 	 */ | ||||
| 	bool readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Set the BME680 sensor's configuration | ||||
| 	 * @param bme680Settings: Settings to configure the BME680 | ||||
| 	 * @return BME680 return code. BME680_OK for success, failure otherwise | ||||
| 	 */ | ||||
| 	int8_t setBme680Config(bsec_bme_settings_t bme680Settings); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Common code for the begin function | ||||
| 	 */ | ||||
| 	void beginCommon(void); | ||||
| 
 | ||||
| 	/**
 | ||||
| 	 * @brief Function to zero the outputs | ||||
| 	 */ | ||||
| 	void zeroOutputs(void); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| @ -6,7 +6,7 @@ | ||||
| 
 | ||||
| ; ---> SELECT TARGET PLATFORM HERE! <--- | ||||
| [platformio] | ||||
| env_default = generic | ||||
| ;env_default = generic | ||||
| ;env_default = ebox | ||||
| ;env_default = eboxtube | ||||
| ;env_default = heltec | ||||
| @ -16,7 +16,7 @@ env_default = generic | ||||
| ;env_default = ttgov21old | ||||
| ;env_default = ttgov21new | ||||
| ;env_default = ttgobeam_old | ||||
| ;env_default = ttgobeam_new | ||||
| env_default = ttgobeam_new | ||||
| ;env_default = lopy | ||||
| ;env_default = lopy4 | ||||
| ;env_default = fipy | ||||
| @ -30,10 +30,10 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng | ||||
| 
 | ||||
| [common] | ||||
| ; for release_version use max. 10 chars total, use any decimal format like "a.b.c" | ||||
| release_version = 1.7.01 | ||||
| release_version = 1.7.03 | ||||
| ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! | ||||
| ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose | ||||
| debug_level = 0 | ||||
| debug_level = 4 | ||||
| ; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA | ||||
| upload_protocol = esptool | ||||
| ;upload_protocol = custom | ||||
|  | ||||
| @ -1,88 +1,89 @@ | ||||
| #ifdef HAS_BME | ||||
| 
 | ||||
| #include "bme680mems.h" | ||||
| #include "bsec.h" | ||||
| 
 | ||||
| // Local logging tag
 | ||||
| static const char TAG[] = "main"; | ||||
| 
 | ||||
| bmeStatus_t bme_status; | ||||
| TaskHandle_t BmeTask; | ||||
| 
 | ||||
| float bme_offset = (float)BME_TEMP_OFFSET; | ||||
| 
 | ||||
| // --- Bosch BSEC library configuration ---
 | ||||
| // 3,3V supply voltage; 3s max time between sensor_control calls; 4 days
 | ||||
| // calibration. Change this const if not applicable for your application (see
 | ||||
| // BME680 datasheet)
 | ||||
| const uint8_t bsec_config_iaq[454] = { | ||||
|     1,   7,   4,   1,   61,  0,   0,   0,   0,   0,   0,   0,   174, 1,   0, | ||||
|     0,   48,  0,   1,   0,   137, 65,  0,   63,  205, 204, 204, 62,  0,   0, | ||||
|     64,  63,  205, 204, 204, 62,  0,   0,   225, 68,  0,   192, 168, 71,  64, | ||||
|     49,  119, 76,  0,   0,   0,   0,   0,   80,  5,   95,  0,   0,   0,   0, | ||||
|     0,   0,   0,   0,   28,  0,   2,   0,   0,   244, 1,   225, 0,   25,  0, | ||||
|     0,   128, 64,  0,   0,   32,  65,  144, 1,   0,   0,   112, 65,  0,   0, | ||||
|     0,   63,  16,  0,   3,   0,   10,  215, 163, 60,  10,  215, 35,  59,  10, | ||||
|     215, 35,  59,  9,   0,   5,   0,   0,   0,   0,   0,   1,   88,  0,   9, | ||||
|     0,   229, 208, 34,  62,  0,   0,   0,   0,   0,   0,   0,   0,   218, 27, | ||||
|     156, 62,  225, 11,  67,  64,  0,   0,   160, 64,  0,   0,   0,   0,   0, | ||||
|     0,   0,   0,   94,  75,  72,  189, 93,  254, 159, 64,  66,  62,  160, 191, | ||||
|     0,   0,   0,   0,   0,   0,   0,   0,   33,  31,  180, 190, 138, 176, 97, | ||||
|     64,  65,  241, 99,  190, 0,   0,   0,   0,   0,   0,   0,   0,   167, 121, | ||||
|     71,  61,  165, 189, 41,  192, 184, 30,  189, 64,  12,  0,   10,  0,   0, | ||||
|     0,   0,   0,   0,   0,   0,   0,   229, 0,   254, 0,   2,   1,   5,   48, | ||||
|     117, 100, 0,   44,  1,   112, 23,  151, 7,   132, 3,   197, 0,   92,  4, | ||||
|     144, 1,   64,  1,   64,  1,   144, 1,   48,  117, 48,  117, 48,  117, 48, | ||||
|     117, 100, 0,   100, 0,   100, 0,   48,  117, 48,  117, 48,  117, 100, 0, | ||||
|     100, 0,   48,  117, 48,  117, 100, 0,   100, 0,   100, 0,   100, 0,   48, | ||||
|     117, 48,  117, 48,  117, 100, 0,   100, 0,   100, 0,   48,  117, 48,  117, | ||||
|     100, 0,   100, 0,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44, | ||||
|     1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1,   44,  1, | ||||
|     44,  1,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8, | ||||
|     7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7,   8,   7, | ||||
|     112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, | ||||
|     23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  112, 23,  255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 220, 5,   220, 5,   220, 5,   255, 255, 255, | ||||
|     255, 255, 255, 220, 5,   220, 5,   255, 255, 255, 255, 255, 255, 255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
|     255, 255, 255, 255, 255, 255, 255, 255, 255, 44,  1,   0,   0,   0,   0, | ||||
|     239, 79,  0,   0}; | ||||
| Bsec iaqSensor; | ||||
| 
 | ||||
| // initialize BME680 sensor
 | ||||
| int bme_init(void) { | ||||
| 
 | ||||
|   // struct bme680_dev gas_sensor;
 | ||||
|   Wire.begin(HAS_BME, 400000); // I2C connect to BME680 sensor with 400 KHz
 | ||||
|   Wire.begin(HAS_BME); | ||||
|   iaqSensor.begin(BME_ADDR, Wire); | ||||
| 
 | ||||
|   // Call to the function which initializes the BSEC library
 | ||||
|   // Switch on low-power mode and provide no temperature offset
 | ||||
|   ESP_LOGI(TAG, "BSEC v%d.%d.%d.%d", iaqSensor.version.major, | ||||
|            iaqSensor.version.minor, iaqSensor.version.major_bugfix, | ||||
|            iaqSensor.version.minor_bugfix); | ||||
| 
 | ||||
|   return_values_init ret = | ||||
|       bsec_iot_init(BSEC_SAMPLE_RATE_LP, bme_offset, i2c_write, i2c_read, | ||||
|                     user_delay_ms, state_load, config_load); | ||||
|   iaqSensor.setConfig(bsec_config_iaq); | ||||
| 
 | ||||
|   if ((int)ret.bme680_status) { | ||||
|     ESP_LOGE(TAG, "Could not initialize BME680, error %d", | ||||
|              (int)ret.bme680_status); | ||||
|   } else if ((int)ret.bsec_status) { | ||||
|     ESP_LOGE(TAG, "Could not initialize BSEC library, error %d", | ||||
|              (int)ret.bsec_status); | ||||
|   } else { | ||||
|   if (checkIaqSensorStatus()) | ||||
|     ESP_LOGI(TAG, "BME680 sensor found and initialized"); | ||||
|   else { | ||||
|     ESP_LOGE(TAG, "BME680 sensor not found"); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   bsec_virtual_sensor_t sensorList[10] = { | ||||
|       BSEC_OUTPUT_RAW_TEMPERATURE, | ||||
|       BSEC_OUTPUT_RAW_PRESSURE, | ||||
|       BSEC_OUTPUT_RAW_HUMIDITY, | ||||
|       BSEC_OUTPUT_RAW_GAS, | ||||
|       BSEC_OUTPUT_IAQ, | ||||
|       BSEC_OUTPUT_STATIC_IAQ, | ||||
|       BSEC_OUTPUT_CO2_EQUIVALENT, | ||||
|       BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, | ||||
|       BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, | ||||
|       BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, | ||||
|   }; | ||||
| 
 | ||||
|   iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); | ||||
| 
 | ||||
|   if (checkIaqSensorStatus()) | ||||
|     ESP_LOGI(TAG, "BSEC subscription succesful"); | ||||
|   else { | ||||
|     ESP_LOGE(TAG, "BSEC subscription error"); | ||||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   iaqSensor.setTemperatureOffset(bme_offset); | ||||
| 
 | ||||
|   if (checkIaqSensorStatus()) | ||||
|     ESP_LOGI(TAG, "Ttemperature offset initialized succesful"); | ||||
|   else { | ||||
|     ESP_LOGE(TAG, "Temperature offset initialization error"); | ||||
|     return 1; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, | ||||
|                   float temperature, float humidity, float pressure, | ||||
|                   float raw_temperature, float raw_humidity, float gas, | ||||
|                   bsec_library_return_t bsec_status, float static_iaq, | ||||
|                   float co2_equivalent, float breath_voc_equivalent) { | ||||
| // Helper function definitions
 | ||||
| int checkIaqSensorStatus(void) { | ||||
|   int rslt = 1; // true = 1 = no error, false = 0 = error
 | ||||
| 
 | ||||
|   bme_status.temperature = temperature; | ||||
|   bme_status.humidity = humidity; | ||||
|   bme_status.pressure = (pressure / 100.0); // conversion Pa -> hPa
 | ||||
|   bme_status.iaq = iaq; | ||||
|   if (iaqSensor.status != BSEC_OK) { | ||||
|     rslt = 0; | ||||
|     if (iaqSensor.status < BSEC_OK) | ||||
|       ESP_LOGE(TAG, "BSEC error %d", iaqSensor.status); | ||||
|     else | ||||
|       ESP_LOGW(TAG, "BSEC warning %d", iaqSensor.status); | ||||
|   } | ||||
| 
 | ||||
|   if (iaqSensor.bme680Status != BME680_OK) { | ||||
|     rslt = 0; | ||||
|     if (iaqSensor.bme680Status < BME680_OK) | ||||
|       ESP_LOGE(TAG, "BME680 error %d", iaqSensor.bme680Status); | ||||
|     else | ||||
|       ESP_LOGW(TAG, "BME680 warning %d", iaqSensor.bme680Status); | ||||
|   } | ||||
| 
 | ||||
|   return rslt; | ||||
| } | ||||
| 
 | ||||
| // loop function which reads and processes data based on sensor settings
 | ||||
| @ -91,84 +92,23 @@ void bme_loop(void *pvParameters) { | ||||
|   configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
 | ||||
| 
 | ||||
| #ifdef HAS_BME | ||||
|   // State is saved every 10.000 samples, which means every 10.000 * 3 secs =
 | ||||
|   // 500 minutes
 | ||||
|   bsec_iot_loop(user_delay_ms, get_timestamp_us, output_ready, state_save, | ||||
|                 10000); | ||||
|   while (checkIaqSensorStatus()) { | ||||
|     if (iaqSensor.run()) { // If new data is available
 | ||||
|       bme_status.raw_temperature = iaqSensor.rawTemperature; | ||||
|       bme_status.raw_humidity = iaqSensor.rawHumidity; | ||||
|       bme_status.temperature = iaqSensor.temperature; | ||||
|       bme_status.humidity = iaqSensor.humidity; | ||||
|       bme_status.pressure = | ||||
|           (iaqSensor.pressure / 100.0); // conversion Pa -> hPa
 | ||||
|       bme_status.iaq = iaqSensor.iaqEstimate; | ||||
|       bme_status.iaq_accuracy = iaqSensor.iaqAccuracy; | ||||
|       bme_status.gas = iaqSensor.gasResistance; | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
|   ESP_LOGE(TAG, "BME task ended"); | ||||
|   vTaskDelete(BmeTask); // should never be reached
 | ||||
| 
 | ||||
| } // bme_loop()
 | ||||
| 
 | ||||
| int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, | ||||
|                 uint16_t len) { | ||||
|   int8_t rslt = 0; | ||||
|   Wire.beginTransmission(dev_id); | ||||
|   Wire.write(reg_addr); | ||||
|   rslt = Wire.endTransmission(false); | ||||
| 
 | ||||
|   Wire.requestFrom((int)dev_id, (int)len); | ||||
|   for (uint16_t i = 0; (i < len) && Wire.available(); i++) { | ||||
|     reg_data[i] = Wire.read(); | ||||
|   } | ||||
|   // return 0 for success, non-zero for failure
 | ||||
|   return rslt; | ||||
| } | ||||
| 
 | ||||
| int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, | ||||
|                  uint16_t len) { | ||||
|   Wire.beginTransmission(dev_id); | ||||
|   Wire.write(reg_addr); | ||||
|   for (uint16_t i = 0; i < len; i++) { | ||||
|     Wire.write(reg_data[i]); | ||||
|   } | ||||
|   // return 0 for success, non-zero for failure
 | ||||
|   return Wire.endTransmission(true); | ||||
| } | ||||
| 
 | ||||
| /*!
 | ||||
|  * @brief           Load previous library state from non-volatile memory | ||||
|  * | ||||
|  * @param[in,out]   state_buffer    buffer to hold the loaded state string | ||||
|  * @param[in]       n_buffer        size of the allocated state buffer | ||||
|  * | ||||
|  * @return          number of bytes copied to state_buffer | ||||
|  */ | ||||
| uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer) { | ||||
|   // ...
 | ||||
|   // Load a previous library state from non-volatile memory, if available.
 | ||||
|   //
 | ||||
|   // Return zero if loading was unsuccessful or no state was available,
 | ||||
|   // otherwise return length of loaded state string.
 | ||||
|   // ...
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| /*!
 | ||||
|  * @brief           Save library state to non-volatile memory | ||||
|  * | ||||
|  * @param[in]       state_buffer    buffer holding the state to be stored | ||||
|  * @param[in]       length          length of the state string to be stored | ||||
|  * | ||||
|  * @return          none | ||||
|  */ | ||||
| void state_save(const uint8_t *state_buffer, uint32_t length) { | ||||
|   // ...
 | ||||
|   // Save the string some form of non-volatile memory, if possible.
 | ||||
|   // ...
 | ||||
| } | ||||
| 
 | ||||
| uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer) { | ||||
| 
 | ||||
|   // Load a library config from non-volatile memory, if available.
 | ||||
|   // Return zero if loading was unsuccessful or no config was available,
 | ||||
|   // otherwise return length of loaded config string.
 | ||||
| 
 | ||||
|   memcpy(config_buffer, bsec_config_iaq, sizeof(bsec_config_iaq)); | ||||
|   return sizeof(bsec_config_iaq); | ||||
| } | ||||
| 
 | ||||
| void user_delay_ms(uint32_t period) { delay(period); } | ||||
| 
 | ||||
| int64_t get_timestamp_us() { return (int64_t)millis() * 1000; } | ||||
| 
 | ||||
| #endif // HAS_BME
 | ||||
| @ -17,8 +17,8 @@ | ||||
| 
 | ||||
| // enable only if device has these sensors, otherwise comment these lines
 | ||||
| // BME680 sensor on I2C bus
 | ||||
| // don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
 | ||||
| #define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | ||||
| #define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | ||||
| 
 | ||||
| // user defined sensors
 | ||||
| //#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | ||||
|  | ||||
| @ -11,11 +11,9 @@ | ||||
| // disable brownout detection (avoid unexpected reset on some boards)
 | ||||
| #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
 | ||||
| 
 | ||||
| // enable only if device has these sensors, otherwise comment these lines
 | ||||
| // BME680 sensor on I2C bus
 | ||||
| // Octopus32 has a pre-populated BME680 on i2c addr 0x76
 | ||||
| #define HAS_BME GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
 | ||||
| //#define HAS_BME 0x76
 | ||||
| #define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | ||||
| 
 | ||||
| // user defined sensors
 | ||||
| //#define HAS_SENSORS 1 // comment out if device has user defined sensors
 | ||||
|  | ||||
| @ -8,12 +8,11 @@ | ||||
| // Hardware related definitions for TTGO T-Beam board
 | ||||
| //
 | ||||
| // pinouts taken from http://tinymicros.com/wiki/TTGO_T-Beam
 | ||||
| //
 | ||||
| 
 | ||||
| // enable only if device has these sensors, otherwise comment these lines
 | ||||
| // BME680 sensor on I2C bus
 | ||||
| // don't forget to connect SDIO of BME680 to GND for selecting i2c addr 0x76
 | ||||
| //
 | ||||
| //#define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | ||||
| #define HAS_BME GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
 | ||||
| #define BME_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
 | ||||
| 
 | ||||
| #define HAS_LED GPIO_NUM_14 // on board green LED
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user