diff --git a/components/bme680/src/bsec2.c b/components/bme680/src/bsec2.c index 8d42c2f..69d7b38 100644 --- a/components/bme680/src/bsec2.c +++ b/components/bme680/src/bsec2.c @@ -1,6 +1,12 @@ #include #include "bsec2.h" +//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + +#include +#include +static const char *TAG = "bsec"; + /* Private funcs - prototypes */ /** @@ -70,7 +76,10 @@ bool bsec2_updateSubscription(struct bsec2 *self, const bsecSensor *sensorList, } bool bsec2_run(struct bsec2 *self) { - int64_t currTimeNs = bsec2_getTimeMs(self) * INT64_C(1000000); + int64_t ms = bsec2_getTimeMs(self); + int64_t currTimeNs = ms * INT64_C(1000000); + + //ESP_LOGD(TAG, "%"PRIi64" ms = %"PRIi64" ns, nextcall %"PRIi64, ms, currTimeNs, self->bmeConf.next_call); uint8_t lastOpMode = self->opMode; @@ -78,6 +87,8 @@ bool bsec2_run(struct bsec2 *self) { self->opMode = self->bmeConf.op_mode; if (currTimeNs >= self->bmeConf.next_call) { + ESP_LOGD(TAG, "bsec runs"); + /* Provides the information about the current sensor configuration that is necessary to fulfill the input requirements, eg: operation mode, timestamp at which the sensor data shall be fetched etc */ @@ -221,14 +232,14 @@ bool bsec2_setConfig(struct bsec2 *self, const uint8_t *config) { * @brief Function to calculate an int64_t timestamp in milliseconds */ int64_t bsec2_getTimeMs(struct bsec2 *self) { - int64_t timeMs = bsec2_timestamp_millis(); - + uint64_t timeMs = bsec2_timestamp_millis(); if (self->lastMillis > timeMs) /* An overflow occurred */ { self->lastMillis = timeMs; self->ovfCounter++; } - return timeMs + (self->ovfCounter * INT64_C(0xFFFFFFFF)); + self->lastMillis = timeMs; + return (int64_t) timeMs + (self->ovfCounter * INT64_C(0xFFFFFFFF)); } /* Private funcs impl */ diff --git a/main/app_main.c b/main/app_main.c index a821df8..d12e20c 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -57,6 +57,8 @@ void app_main(void) { periph_init(); + vTaskDelay(pdMS_TO_TICKS(1000)); + xTaskCreatePinnedToCore(voc_read_task, "VOC", 4096, NULL, PRIO_NORMAL, NULL, 1); xTaskCreatePinnedToCore(co2_read_task, "CO2", 4096, NULL, PRIO_NORMAL, NULL, 1); diff --git a/main/co2_sensor.c b/main/co2_sensor.c index 2b2fa2e..f48ba34 100644 --- a/main/co2_sensor.c +++ b/main/co2_sensor.c @@ -15,7 +15,8 @@ static const char *TAG = "co2"; #define CO2_ADDR 104 #define CO2_I2C_NUM I2C_NUM_0 -#define TIMEOUT_MS 1000 +#define TIMEOUT_MS 500 +#define SEMA_TIMEOUT_MS 2000 static esp_err_t do_reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { i2c_cmd_handle_t cmd = i2c_cmd_link_create(); @@ -42,10 +43,11 @@ bool wake_up() { TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_READ, false)); // TODO expect ack? TRY(i2c_master_read(chain, &dummy, 1, I2C_MASTER_LAST_NACK)); TRY(i2c_master_stop(chain)); - /*esp_err_t ret = */ i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(10)); + /*esp_err_t ret = */ i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(TIMEOUT_MS)); i2c_cmd_link_delete(chain); // if (ret == ESP_OK) { - vTaskDelay(pdMS_TO_TICKS(14)); +// ets_delay_us(5000); + ets_delay_us(12000); return true; // } //// } @@ -55,7 +57,7 @@ bool wake_up() { } static esp_err_t reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { - BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(500)); + BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); if (suc != pdPASS) { ESP_LOGE(TAG, "Sema fail"); return ESP_ERR_TIMEOUT; @@ -66,7 +68,7 @@ static esp_err_t reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, } esp_err_t rv = do_reg_read(reg_addr, reg_data, length, timeout_ms); xSemaphoreGive(g_mux_i2c); - ets_delay_us(12000); + vTaskDelay(pdMS_TO_TICKS(12)); return rv; } @@ -82,7 +84,7 @@ static esp_err_t do_reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_ } static esp_err_t reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { - BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(500)); + BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); if (suc != pdPASS) { ESP_LOGE(TAG, "Sema fail"); return ESP_ERR_TIMEOUT; @@ -102,32 +104,42 @@ void co2_read_task(void *param) { // continuous is the default - vTaskDelay(pdMS_TO_TICKS(35)); - - { - uint8_t pld[] = {0x00, 0x07, 0x00, 0x05}; - reg_write(0x96, pld, 4, TIMEOUT_MS); + for (int retry = 1; retry <= 10; retry++) { + uint8_t pld[] = {0x00, 0x05, 0x00, 0x05}; + if (ESP_OK == reg_write(0x96, pld, 4, TIMEOUT_MS)) { + ESP_LOGI(TAG, "CO2 init OK"); + break; + } + vTaskDelay(pdMS_TO_TICKS(50)); } + vTaskDelay(pdMS_TO_TICKS(250)); while (1) { - vTaskDelay(pdMS_TO_TICKS(7000)); + vTaskDelay(pdMS_TO_TICKS(5000)); uint8_t data[4] = {}; - if (ESP_OK == reg_read(0x06, data, 4, TIMEOUT_MS)) { - uint16_t filtered = (data[0] << 8) | data[1]; - uint16_t unfiltered = (data[2] << 8) | data[3]; - - ESP_LOGI(TAG, "CO2 ppm %d, raw %d", filtered, unfiltered); - - if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(1000))) { - if (filtered > 400 && filtered < 5000) { - g_data_report.co2_ppm = (float) filtered; - g_data_report.co2_ready = true; - } else { - g_data_report.co2_ready = false; + + for (int retry = 0; retry < 3; retry++) { + if (ESP_OK == reg_read(0x06, data, 4, TIMEOUT_MS)) { + uint16_t filtered = (data[0] << 8) | data[1]; + uint16_t unfiltered = (data[2] << 8) | data[3]; + + ESP_LOGI(TAG, "CO2 ppm %d, raw %d", filtered, unfiltered); + + if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(1000))) { + if (filtered > 400 && filtered < 5000) { + g_data_report.co2_ppm = (float) filtered; + g_data_report.co2_ready = true; + g_data_report.co2_timestamp = xTaskGetTickCount(); + } else { + g_data_report.co2_ready = false; + } } + xSemaphoreGive(g_mux_data_report); + break; } - xSemaphoreGive(g_mux_data_report); + + vTaskDelay(pdMS_TO_TICKS(50)); } } } diff --git a/main/data_report.h b/main/data_report.h index 26c2e49..a7d2c97 100644 --- a/main/data_report.h +++ b/main/data_report.h @@ -11,24 +11,34 @@ #include #include #include +#include struct data_report { bool iaq_ready; + uint32_t iaq_timestamp; float iaq; float iaq_static; float iaq_co2_ppm_equiv; float iaq_voc_ppm_equiv; bool thpg_ready; + uint32_t thpg_timestamp; float temperature; float pressure; float humidity; float gasr; bool co2_ready; + uint32_t co2_timestamp; float co2_ppm; }; +static inline uint32_t timestamp_age(uint32_t ticks) { + return xTaskGetTickCount() - ticks; +} + +#define DATA_MAX_AGE (pdMS_TO_TICKS(60000)) + extern SemaphoreHandle_t g_mux_data_report; extern struct data_report g_data_report; diff --git a/main/voc_sensor.c b/main/voc_sensor.c index 70cbe9e..138d033 100644 --- a/main/voc_sensor.c +++ b/main/voc_sensor.c @@ -14,6 +14,7 @@ static const char *TAG = "voc"; #define VOC_I2C_NUM I2C_NUM_0 #define VOC_I2C_TO_MS 1000 +#define VOC_SEMA_TO_MS 2000 // Config overrides for BSEC #define BME68X_PERIOD_POLL UINT32_C(5000) @@ -70,7 +71,7 @@ static BME68X_INTF_RET_TYPE user_i2c_read(uint8_t reg_addr, uint8_t *reg_data, u if (length == 0) { return BME68X_OK; } - BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(500)); + BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(VOC_SEMA_TO_MS)); if (suc != pdPASS) { ESP_LOGE(TAG, "Sema fail"); return -1; @@ -93,7 +94,7 @@ static BME68X_INTF_RET_TYPE user_i2c_write(uint8_t reg_addr, const uint8_t *reg_ if (length == 0) { return BME68X_OK; } - BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(500)); + BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(VOC_SEMA_TO_MS)); if (suc != pdPASS) { ESP_LOGE(TAG, "Sema fail"); return -1; @@ -120,8 +121,8 @@ static esp_err_t voc_init(void) { gas_sensor.write = user_i2c_write; gas_sensor.delay_us = user_delay_us; - for (int retry = 0; retry < 3; retry++) { - ESP_LOGD(TAG, "BME680 initializing"); + for (int retry = 1; retry <= 3; retry++) { + ESP_LOGD(TAG, "BME680 initializing (try %d)", retry); rslt = bme68x_init(&gas_sensor); if (rslt == BME68X_OK) { break; @@ -131,6 +132,7 @@ static esp_err_t voc_init(void) { ESP_LOGE(TAG, "Error from bme680_init: %d", rslt); return ESP_FAIL; } + ESP_LOGI(TAG, "BME680 init OK"); return ESP_OK; } @@ -203,6 +205,7 @@ static void new_data_callback( if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(1000))) { if (my_report.thpg_ready) { g_data_report.thpg_ready = true; + g_data_report.thpg_timestamp = xTaskGetTickCount(); g_data_report.humidity = my_report.humidity; g_data_report.temperature = my_report.temperature; g_data_report.pressure = my_report.pressure; @@ -213,6 +216,7 @@ static void new_data_callback( if (my_report.iaq_ready) { g_data_report.iaq_ready = true; + g_data_report.iaq_timestamp = xTaskGetTickCount(); g_data_report.iaq = my_report.iaq; g_data_report.iaq_static = my_report.iaq_static; g_data_report.iaq_co2_ppm_equiv = my_report.iaq_co2_ppm_equiv; @@ -285,5 +289,6 @@ void voc_read_task(void *param) { } abort: + ESP_LOGE(TAG, "VOC task ends"); vTaskDelete(NULL); } diff --git a/main/web/websrv.c b/main/web/websrv.c index 91a8ad8..145cb5c 100644 --- a/main/web/websrv.c +++ b/main/web/websrv.c @@ -93,22 +93,34 @@ static esp_err_t handler_sample(httpd_req_t *req) { bool need_comma = false; if (g_data_report.iaq_ready) { - wp += sprintf(wp, "\"iaq\":%.2f,\"iaq_s\":%.2f,\"iaq_co2\":%.2f,\"iaq_voc\":%.2f", - g_data_report.iaq,g_data_report.iaq_static, g_data_report.iaq_co2_ppm_equiv, g_data_report.iaq_co2_ppm_equiv); - need_comma = true; + if (timestamp_age(g_data_report.iaq_timestamp) < DATA_MAX_AGE) { + wp += sprintf(wp, "\"iaq\":%.2f,\"iaq_s\":%.2f,\"iaq_co2\":%.2f,\"iaq_voc\":%.2f", + g_data_report.iaq, g_data_report.iaq_static, g_data_report.iaq_co2_ppm_equiv, g_data_report.iaq_co2_ppm_equiv); + need_comma = true; + } else { + g_data_report.iaq_ready = false; + } } if (g_data_report.thpg_ready) { - wp += sprintf(wp, "%s\"temp\":%.2f,\"hum\":%.2f,\"pres\":%.1f,\"gasr\":%.1f", - need_comma?",":"", - g_data_report.temperature,g_data_report.humidity, g_data_report.pressure, g_data_report.gasr); - need_comma = true; + if (timestamp_age(g_data_report.thpg_timestamp) < DATA_MAX_AGE) { + wp += sprintf(wp, "%s\"temp\":%.2f,\"hum\":%.2f,\"pres\":%.1f,\"gasr\":%.1f", + need_comma ? "," : "", + g_data_report.temperature, g_data_report.humidity, g_data_report.pressure, g_data_report.gasr); + need_comma = true; + } else { + g_data_report.thpg_ready = false; + } } if (g_data_report.co2_ready) { - wp += sprintf(wp, "%s\"co2\":%.2f", - need_comma?",":"", - g_data_report.co2_ppm); + if (timestamp_age(g_data_report.co2_timestamp) < DATA_MAX_AGE) { + wp += sprintf(wp, "%s\"co2\":%.2f", + need_comma ? "," : "", + g_data_report.co2_ppm); + } else { + g_data_report.co2_ready = false; + } } sprintf(wp, "}");