first fully functional integration (experimental)

This commit is contained in:
Klaus K Wilting 2018-12-27 17:09:40 +01:00
parent eb5dac2dea
commit 76600a86b1
10 changed files with 488 additions and 446 deletions

View File

@ -89,6 +89,7 @@ extern uint8_t volatile channel; // wifi channel rotation counter
extern uint16_t volatile macs_total, macs_wifi, macs_ble, extern uint16_t volatile macs_total, macs_wifi, macs_ble,
batt_voltage; // display values batt_voltage; // display values
extern hw_timer_t *channelSwitch, *sendCycle, *displaytimer; extern hw_timer_t *channelSwitch, *sendCycle, *displaytimer;
extern SemaphoreHandle_t I2Caccess;
extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs; extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
extern std::array<uint64_t, 0xff>::iterator it; extern std::array<uint64_t, 0xff>::iterator it;

View File

@ -103,7 +103,7 @@
/** BME680 configuration macros */ /** BME680 configuration macros */
/** Enable or un-comment the macro to provide floating point data output */ /** Enable or un-comment the macro to provide floating point data output */
#ifndef BME680_FLOAT_POINT_COMPENSATION #ifndef BME680_FLOAT_POINT_COMPENSATION
/* #define BME680_FLOAT_POINT_COMPENSATION */ //#define BME680_FLOAT_POINT_COMPENSATION
#endif #endif
/** BME680 General config */ /** BME680 General config */

View File

@ -47,14 +47,13 @@
#include "bsec.h" #include "bsec.h"
TwoWire* Bsec::wireObj = NULL; TwoWire *Bsec::wireObj = NULL;
SPIClass* Bsec::spiObj = NULL; SPIClass *Bsec::spiObj = NULL;
/** /**
* @brief Constructor * @brief Constructor
*/ */
Bsec::Bsec() Bsec::Bsec() {
{
nextCall = 0; nextCall = 0;
version.major = 0; version.major = 0;
version.minor = 0; version.minor = 0;
@ -72,8 +71,8 @@ Bsec::Bsec()
/** /**
* @brief Function to initialize the BSEC library and the BME680 sensor * @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) 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.dev_id = devId;
_bme680.intf = intf; _bme680.intf = intf;
_bme680.read = read; _bme680.read = read;
@ -88,8 +87,7 @@ void Bsec::begin(uint8_t devId, enum bme680_intf intf, bme680_com_fptr_t read, b
/** /**
* @brief Function to initialize the BSEC library and the BME680 sensor * @brief Function to initialize the BSEC library and the BME680 sensor
*/ */
void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c) void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c) {
{
_bme680.dev_id = i2cAddr; _bme680.dev_id = i2cAddr;
_bme680.intf = BME680_I2C_INTF; _bme680.intf = BME680_I2C_INTF;
_bme680.read = Bsec::i2cRead; _bme680.read = Bsec::i2cRead;
@ -107,8 +105,7 @@ void Bsec::begin(uint8_t i2cAddr, TwoWire &i2c)
/** /**
* @brief Function to initialize the BSEC library and the BME680 sensor * @brief Function to initialize the BSEC library and the BME680 sensor
*/ */
void Bsec::begin(uint8_t chipSelect, SPIClass &spi) void Bsec::begin(uint8_t chipSelect, SPIClass &spi) {
{
_bme680.dev_id = chipSelect; _bme680.dev_id = chipSelect;
_bme680.intf = BME680_SPI_INTF; _bme680.intf = BME680_SPI_INTF;
_bme680.read = Bsec::spiTransfer; _bme680.read = Bsec::spiTransfer;
@ -128,8 +125,7 @@ void Bsec::begin(uint8_t chipSelect, SPIClass &spi)
/** /**
* @brief Common code for the begin function * @brief Common code for the begin function
*/ */
void Bsec::beginCommon(void) void Bsec::beginCommon(void) {
{
status = bsec_init(); status = bsec_init();
getVersion(); getVersion();
@ -140,8 +136,8 @@ void Bsec::beginCommon(void)
/** /**
* @brief Function that sets the desired sensors and the sample rates * @brief Function that sets the desired sensors and the sample rates
*/ */
void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSensors, float sampleRate) void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[],
{ uint8_t nSensors, float sampleRate) {
bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS], bsec_sensor_configuration_t virtualSensors[BSEC_NUMBER_OUTPUTS],
sensorSettings[BSEC_MAX_PHYSICAL_SENSOR]; sensorSettings[BSEC_MAX_PHYSICAL_SENSOR];
uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR; uint8_t nVirtualSensors = 0, nSensorSettings = BSEC_MAX_PHYSICAL_SENSOR;
@ -152,15 +148,16 @@ void Bsec::updateSubscription(bsec_virtual_sensor_t sensorList[], uint8_t nSenso
nVirtualSensors++; nVirtualSensors++;
} }
status = bsec_update_subscription(virtualSensors, nVirtualSensors, sensorSettings, &nSensorSettings); status = bsec_update_subscription(virtualSensors, nVirtualSensors,
sensorSettings, &nSensorSettings);
return; return;
} }
/** /**
* @brief Callback from the user to trigger reading of data from the BME680, process and store outputs * @brief Callback from the user to trigger reading of data from the BME680,
* process and store outputs
*/ */
bool Bsec::run(void) bool Bsec::run(void) {
{
bool newData = false; bool newData = false;
/* Check if the time has arrived to call do_steps() */ /* Check if the time has arrived to call do_steps() */
int64_t callTimeMs = getTimeMs(); int64_t callTimeMs = getTimeMs();
@ -175,7 +172,8 @@ bool Bsec::run(void)
if (status < BSEC_OK) if (status < BSEC_OK)
return false; return false;
nextCall = bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms nextCall =
bme680Settings.next_call / INT64_C(1000000); // Convert from ns to ms
bme680Status = setBme680Config(bme680Settings); bme680Status = setBme680Config(bme680Settings);
if (bme680Status != BME680_OK) { if (bme680Status != BME680_OK) {
@ -200,33 +198,34 @@ bool Bsec::run(void)
} }
/** /**
* @brief Function to get the state of the algorithm to save to non-volatile memory * @brief Function to get the state of the algorithm to save to non-volatile
* memory
*/ */
void Bsec::getState(uint8_t *state) void Bsec::getState(uint8_t *state) {
{
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
uint32_t n_serialized_state = 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); 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 * @brief Function to set the state of the algorithm from non-volatile memory
*/ */
void Bsec::setState(uint8_t *state) void Bsec::setState(uint8_t *state) {
{
uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE]; uint8_t workBuffer[BSEC_MAX_STATE_BLOB_SIZE];
status = bsec_set_state(state, BSEC_MAX_STATE_BLOB_SIZE, 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 * @brief Function to set the configuration of the algorithm from memory
*/ */
void Bsec::setConfig(const uint8_t *state) void Bsec::setConfig(const uint8_t *state) {
{
uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE]; uint8_t workBuffer[BSEC_MAX_PROPERTY_BLOB_SIZE];
status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE, workBuffer, sizeof(workBuffer)); status = bsec_set_configuration(state, BSEC_MAX_PROPERTY_BLOB_SIZE,
workBuffer, sizeof(workBuffer));
} }
/* Private functions */ /* Private functions */
@ -234,16 +233,13 @@ void Bsec::setConfig(const uint8_t *state)
/** /**
* @brief Get the version of the BSEC library * @brief Get the version of the BSEC library
*/ */
void Bsec::getVersion(void) void Bsec::getVersion(void) { bsec_get_version(&version); }
{
bsec_get_version(&version);
}
/** /**
* @brief Read data from the BME680 and process it * @brief Read data from the BME680 and process it
*/ */
bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Settings) bool Bsec::readProcessData(int64_t currTimeNs,
{ bsec_bme_settings_t bme680Settings) {
bme680Status = bme680_get_sensor_data(&_data, &_bme680); bme680Status = bme680_get_sensor_data(&_data, &_bme680);
if (bme680Status != BME680_OK) { if (bme680Status != BME680_OK) {
return false; return false;
@ -255,10 +251,15 @@ bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Setting
if (_data.status & BME680_NEW_DATA_MSK) { if (_data.status & BME680_NEW_DATA_MSK) {
if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) { if (bme680Settings.process_data & BSEC_PROCESS_TEMPERATURE) {
inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE; inputs[nInputs].sensor_id = BSEC_INPUT_TEMPERATURE;
#ifdef BME680_FLOAT_POINT_COMPENSATION
inputs[nInputs].signal = _data.temperature; inputs[nInputs].signal = _data.temperature;
#else
inputs[nInputs].signal = _data.temperature / 100.0f;
#endif
inputs[nInputs].time_stamp = currTimeNs; inputs[nInputs].time_stamp = currTimeNs;
nInputs++; nInputs++;
/* Temperature offset from the real temperature due to external heat sources */ /* Temperature offset from the real temperature due to external heat
* sources */
inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE; inputs[nInputs].sensor_id = BSEC_INPUT_HEATSOURCE;
inputs[nInputs].signal = _tempOffset; inputs[nInputs].signal = _tempOffset;
inputs[nInputs].time_stamp = currTimeNs; inputs[nInputs].time_stamp = currTimeNs;
@ -266,7 +267,11 @@ bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Setting
} }
if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) { if (bme680Settings.process_data & BSEC_PROCESS_HUMIDITY) {
inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY; inputs[nInputs].sensor_id = BSEC_INPUT_HUMIDITY;
#ifdef BME680_FLOAT_POINT_COMPENSATION
inputs[nInputs].signal = _data.humidity; inputs[nInputs].signal = _data.humidity;
#else
inputs[nInputs].signal = _data.humidity / 1000.0f;
#endif
inputs[nInputs].time_stamp = currTimeNs; inputs[nInputs].time_stamp = currTimeNs;
nInputs++; nInputs++;
} }
@ -295,7 +300,8 @@ bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Setting
zeroOutputs(); zeroOutputs();
if (nOutputs > 0) { if (nOutputs > 0) {
outputTimestamp = _outputs[0].time_stamp / 1000000; // Convert from ns to ms outputTimestamp =
_outputs[0].time_stamp / 1000000; // Convert from ns to ms
for (uint8_t i = 0; i < nOutputs; i++) { for (uint8_t i = 0; i < nOutputs; i++) {
switch (_outputs[i].sensor_id) { switch (_outputs[i].sensor_id) {
@ -361,24 +367,22 @@ bool Bsec::readProcessData(int64_t currTimeNs, bsec_bme_settings_t bme680Setting
/** /**
* @brief Set the BME680 sensor's configuration * @brief Set the BME680 sensor's configuration
*/ */
int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) int8_t Bsec::setBme680Config(bsec_bme_settings_t bme680Settings) {
{
_bme680.gas_sett.run_gas = bme680Settings.run_gas; _bme680.gas_sett.run_gas = bme680Settings.run_gas;
_bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling; _bme680.tph_sett.os_hum = bme680Settings.humidity_oversampling;
_bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling; _bme680.tph_sett.os_temp = bme680Settings.temperature_oversampling;
_bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling; _bme680.tph_sett.os_pres = bme680Settings.pressure_oversampling;
_bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature; _bme680.gas_sett.heatr_temp = bme680Settings.heater_temperature;
_bme680.gas_sett.heatr_dur = bme680Settings.heating_duration; _bme680.gas_sett.heatr_dur = bme680Settings.heating_duration;
uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL uint16_t desired_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL |
| BME680_GAS_SENSOR_SEL; BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
return bme680_set_sensor_settings(desired_settings, &_bme680); return bme680_set_sensor_settings(desired_settings, &_bme680);
} }
/** /**
* @brief Function to zero the outputs * @brief Function to zero the outputs
*/ */
void Bsec::zeroOutputs(void) void Bsec::zeroOutputs(void) {
{
temperature = 0.0f; temperature = 0.0f;
pressure = 0.0f; pressure = 0.0f;
humidity = 0.0f; humidity = 0.0f;
@ -404,8 +408,7 @@ void Bsec::zeroOutputs(void)
/** /**
* @brief Function to calculate an int64_t timestamp in milliseconds * @brief Function to calculate an int64_t timestamp in milliseconds
*/ */
int64_t Bsec::getTimeMs(void) int64_t Bsec::getTimeMs(void) {
{
int64_t timeMs = millis(); int64_t timeMs = millis();
if (lastTime > timeMs) { // An overflow occured if (lastTime > timeMs) { // An overflow occured
@ -419,8 +422,7 @@ int64_t Bsec::getTimeMs(void)
/** /**
@brief Task that delays for a ms period of time @brief Task that delays for a ms period of time
*/ */
void Bsec::delay_ms(uint32_t period) void Bsec::delay_ms(uint32_t period) {
{
// Wait for a period amount of ms // Wait for a period amount of ms
// The system may simply idle, sleep or even perform background tasks // The system may simply idle, sleep or even perform background tasks
delay(period); delay(period);
@ -429,15 +431,15 @@ void Bsec::delay_ms(uint32_t period)
/** /**
@brief Callback function for reading registers over I2C @brief Callback function for reading registers over I2C
*/ */
int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData,
{ uint16_t length) {
uint16_t i; uint16_t i;
int8_t rslt = 0; int8_t rslt = 0;
if(Bsec::wireObj) { if (Bsec::wireObj) {
Bsec::wireObj->beginTransmission(devId); Bsec::wireObj->beginTransmission(devId);
Bsec::wireObj->write(regAddr); Bsec::wireObj->write(regAddr);
rslt = Bsec::wireObj->endTransmission(); rslt = Bsec::wireObj->endTransmission();
Bsec::wireObj->requestFrom((int) devId, (int) length); Bsec::wireObj->requestFrom((int)devId, (int)length);
for (i = 0; (i < length) && Bsec::wireObj->available(); i++) { for (i = 0; (i < length) && Bsec::wireObj->available(); i++) {
regData[i] = Bsec::wireObj->read(); regData[i] = Bsec::wireObj->read();
} }
@ -450,11 +452,11 @@ int8_t Bsec::i2cRead(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t
/** /**
* @brief Callback function for writing registers over I2C * @brief Callback function for writing registers over I2C
*/ */
int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t length) int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData,
{ uint16_t length) {
uint16_t i; uint16_t i;
int8_t rslt = 0; int8_t rslt = 0;
if(Bsec::wireObj) { if (Bsec::wireObj) {
Bsec::wireObj->beginTransmission(devId); Bsec::wireObj->beginTransmission(devId);
Bsec::wireObj->write(regAddr); Bsec::wireObj->write(regAddr);
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
@ -471,15 +473,17 @@ int8_t Bsec::i2cWrite(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint16_t
/** /**
* @brief Callback function for reading and writing registers over SPI * @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 Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData,
{ uint16_t length) {
int8_t rslt = 0; int8_t rslt = 0;
if(Bsec::spiObj) { if (Bsec::spiObj) {
Bsec::spiObj->beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz Bsec::spiObj->beginTransaction(
SPISettings(4000000, MSBFIRST, SPI_MODE0)); // Can be upto 10MHz
digitalWrite(devId, LOW); digitalWrite(devId, LOW);
Bsec::spiObj->transfer(regAddr); // Write the register address, ignore the return Bsec::spiObj->transfer(
regAddr); // Write the register address, ignore the return
for (uint16_t i = 0; i < length; i++) for (uint16_t i = 0; i < length; i++)
regData[i] = Bsec::spiObj->transfer(regData[i]); regData[i] = Bsec::spiObj->transfer(regData[i]);
@ -489,5 +493,6 @@ int8_t Bsec::spiTransfer(uint8_t devId, uint8_t regAddr, uint8_t *regData, uint1
rslt = -1; rslt = -1;
} }
return rslt;; return rslt;
;
} }

View File

@ -33,7 +33,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
release_version = 1.7.03 release_version = 1.7.03
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 4 debug_level = 3
; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA ; UPLOAD MODE: select esptool to flash via USB/UART, select custom to upload to cloud for OTA
upload_protocol = esptool upload_protocol = esptool
;upload_protocol = custom ;upload_protocol = custom

View File

@ -7,13 +7,29 @@ static const char TAG[] = "main";
bmeStatus_t bme_status; bmeStatus_t bme_status;
TaskHandle_t BmeTask; TaskHandle_t BmeTask;
float bme_offset = (float)BME_TEMP_OFFSET;
Bsec iaqSensor; Bsec iaqSensor;
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,
};
// initialize BME680 sensor // initialize BME680 sensor
int bme_init(void) { int bme_init(void) {
// block i2c bus access
if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
pdTRUE) {
Wire.begin(HAS_BME); Wire.begin(HAS_BME);
iaqSensor.begin(BME_ADDR, Wire); iaqSensor.begin(BME_ADDR, Wire);
@ -30,19 +46,7 @@ int bme_init(void) {
return 1; return 1;
} }
bsec_virtual_sensor_t sensorList[10] = { iaqSensor.setTemperatureOffset((float)BME_TEMP_OFFSET);
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); iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
if (checkIaqSensorStatus()) if (checkIaqSensorStatus())
@ -52,15 +56,14 @@ int bme_init(void) {
return 1; return 1;
} }
iaqSensor.setTemperatureOffset(bme_offset); xSemaphoreGive(I2Caccess); // release i2c bus access
if (checkIaqSensorStatus()) } else {
ESP_LOGI(TAG, "Ttemperature offset initialized succesful"); ESP_LOGE(TAG, "I2c bus busy - BME680 initialization error");
else {
ESP_LOGE(TAG, "Temperature offset initialization error");
return 1; return 1;
} }
}
} // bme_init()
// Helper function definitions // Helper function definitions
int checkIaqSensorStatus(void) { int checkIaqSensorStatus(void) {
@ -83,7 +86,7 @@ int checkIaqSensorStatus(void) {
} }
return rslt; return rslt;
} } // checkIaqSensorStatus()
// loop function which reads and processes data based on sensor settings // loop function which reads and processes data based on sensor settings
void bme_loop(void *pvParameters) { void bme_loop(void *pvParameters) {
@ -92,6 +95,11 @@ void bme_loop(void *pvParameters) {
#ifdef HAS_BME #ifdef HAS_BME
while (checkIaqSensorStatus()) { while (checkIaqSensorStatus()) {
// block i2c bus access
if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
pdTRUE) {
if (iaqSensor.run()) { // If new data is available if (iaqSensor.run()) { // If new data is available
bme_status.raw_temperature = iaqSensor.rawTemperature; bme_status.raw_temperature = iaqSensor.rawTemperature;
bme_status.raw_humidity = iaqSensor.rawHumidity; bme_status.raw_humidity = iaqSensor.rawHumidity;
@ -103,6 +111,9 @@ void bme_loop(void *pvParameters) {
bme_status.iaq_accuracy = iaqSensor.iaqAccuracy; bme_status.iaq_accuracy = iaqSensor.iaqAccuracy;
bme_status.gas = iaqSensor.gasResistance; bme_status.gas = iaqSensor.gasResistance;
} }
xSemaphoreGive(I2Caccess); // release i2c bus access
}
} }
#endif #endif
ESP_LOGE(TAG, "BME task ended"); ESP_LOGE(TAG, "BME task ended");

View File

@ -52,7 +52,12 @@ void doHousekeeping() {
// read battery voltage into global variable // read battery voltage into global variable
#ifdef HAS_BATTERY_PROBE #ifdef HAS_BATTERY_PROBE
batt_voltage = read_voltage(); batt_voltage = read_voltage();
ESP_LOGI(TAG, "Measured Voltage: %dmV", batt_voltage); ESP_LOGI(TAG, "Voltage: %dmV", batt_voltage);
#endif
// display BME sensor data if present
#ifdef HAS_BME
ESP_LOGI(TAG, "BME680 Temp: %.2f°C | IAQ: %.2f", bme_status.temperature, bme_status.iaq);
#endif #endif
// check free heap memory // check free heap memory

View File

@ -98,6 +98,10 @@ void init_display(const char *Productname, const char *Version) {
void refreshtheDisplay() { void refreshtheDisplay() {
// block i2c bus access
if (xSemaphoreTake(I2Caccess, (DISPLAYREFRESH_MS / portTICK_PERIOD_MS)) ==
pdTRUE) {
// set display on/off according to current device configuration // set display on/off according to current device configuration
if (DisplayState != cfg.screenon) { if (DisplayState != cfg.screenon) {
DisplayState = cfg.screenon; DisplayState = cfg.screenon;
@ -114,7 +118,8 @@ void refreshtheDisplay() {
// update counter (lines 0-1) // update counter (lines 0-1)
snprintf( snprintf(
buff, sizeof(buff), "PAX:%-4d", buff, sizeof(buff), "PAX:%-4d",
(int)macs.size()); // convert 16-bit MAC counter to decimal counter value (int)
macs.size()); // convert 16-bit MAC counter to decimal counter value
u8x8.draw2x2String(0, 0, u8x8.draw2x2String(0, 0,
buff); // display number on unique macs total Wifi + BLE buff); // display number on unique macs total Wifi + BLE
@ -188,6 +193,9 @@ void refreshtheDisplay() {
#endif // HAS_LORA #endif // HAS_LORA
xSemaphoreGive(I2Caccess); // release i2c bus access
}
} // refreshDisplay() } // refreshDisplay()
#endif // HAS_DISPLAY #endif // HAS_DISPLAY

View File

@ -19,10 +19,10 @@
// user defined sensors // user defined sensors
//#define HAS_SENSORS 1 // comment out if device has user defined sensors //#define HAS_SENSORS 1 // comment out if device has user defined sensors
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
//#define MY_OLED_SDA (21) #define MY_OLED_SDA (21)
//#define MY_OLED_SCL (22) #define MY_OLED_SCL (22)
//#define MY_OLED_RST (NOT_A_PIN) #define MY_OLED_RST U8X8_PIN_NONE
//#define DISPLAY_FLIP 1 // use if display is rotated //#define DISPLAY_FLIP 1 // use if display is rotated
#define HAS_LORA 1 // comment out if device shall not send data via LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa

View File

@ -22,7 +22,7 @@
//#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C //#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
//#define MY_OLED_SDA (21) //#define MY_OLED_SDA (21)
//#define MY_OLED_SCL (22) //#define MY_OLED_SCL (22)
//#define MY_OLED_RST (NOT_A_PIN) //#define MY_OLED_RST U8X8_PIN_NONE
//#define DISPLAY_FLIP 1 // use if display is rotated //#define DISPLAY_FLIP 1 // use if display is rotated
#define HAS_LORA 1 // comment out if device shall not send data via LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa

View File

@ -35,11 +35,14 @@ IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
looptask 1 1 arduino core -> runs the LMIC LoRa stack looptask 1 1 arduino core -> runs the LMIC LoRa stack
irqhandler 1 1 executes tasks triggered by irq irqhandler 1 1 executes tasks triggered by irq
gpsloop 1 2 reads data from GPS via serial or i2c gpsloop 1 2 reads data from GPS via serial or i2c
bmeloop 1 0 reads data from BME sensor via i2c bmeloop 1 1 reads data from BME sensor via i2c
IDLE 1 0 ESP32 arduino scheduler IDLE 1 0 ESP32 arduino scheduler
Low priority numbers denote low priority tasks. Low priority numbers denote low priority tasks.
Tasks using i2c bus all must have same priority, because using mutex semaphore
(irqhandler, bmeloop)
ESP32 hardware timers ESP32 hardware timers
========================== ==========================
0 Trigger display refresh 0 Trigger display refresh
@ -60,6 +63,7 @@ uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL, hw_timer_t *channelSwitch = NULL, *sendCycle = NULL, *homeCycle = NULL,
*displaytimer = NULL; // irq tasks *displaytimer = NULL; // irq tasks
TaskHandle_t irqHandlerTask, wifiSwitchTask; TaskHandle_t irqHandlerTask, wifiSwitchTask;
SemaphoreHandle_t I2Caccess;
// container holding unique MAC address hashes with Memory Alloctor using PSRAM, // container holding unique MAC address hashes with Memory Alloctor using PSRAM,
// if present // if present
@ -78,6 +82,14 @@ void setup() {
char features[100] = ""; char features[100] = "";
if (I2Caccess == NULL) // Check that semaphore has not already been created
{
I2Caccess = xSemaphoreCreateMutex(); // Create a mutex semaphore we will use
// to manage the i2c bus
if ((I2Caccess) != NULL)
xSemaphoreGive((I2Caccess)); // Flag the i2c bus available for use
}
// disable brownout detection // disable brownout detection
#ifdef DISABLE_BROWNOUT #ifdef DISABLE_BROWNOUT
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4 // register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
@ -343,11 +355,11 @@ void setup() {
"bmeloop", // name of task "bmeloop", // name of task
4096, // stack size of task 4096, // stack size of task
(void *)1, // parameter of the task (void *)1, // parameter of the task
0, // priority of the task //0, // priority of the task
1, // priority of the task
&BmeTask, // task handle &BmeTask, // task handle
1); // CPU core 1); // CPU core
} }
delay(2000); // time for initializing i2c sensor
#endif #endif
// start timer triggered interrupts // start timer triggered interrupts