summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2022-01-02 18:07:49 +0100
committerDaniel Friesel <derf@finalrewind.org>2022-01-02 18:07:49 +0100
commitb78f595070a41037a7df04e103a959b6ad68a7bd (patch)
tree5c13c4952e39e9680f61747080018b5b54707a0b
parent0319d8f5321cc0f712c7d3dc82362235490995b7 (diff)
bme680-max44009-logger: add POSIX variant with BSEC support
-rw-r--r--src/app/bme680-max44009-logger/Kconfig6
-rw-r--r--src/app/bme680-max44009-logger/Makefile.inc8
-rw-r--r--src/app/bme680-max44009-logger/generic.cc161
-rw-r--r--src/app/bme680-max44009-logger/main.cc162
-rw-r--r--src/app/bme680-max44009-logger/posix.cc320
5 files changed, 499 insertions, 158 deletions
diff --git a/src/app/bme680-max44009-logger/Kconfig b/src/app/bme680-max44009-logger/Kconfig
new file mode 100644
index 0000000..161e351
--- /dev/null
+++ b/src/app/bme680-max44009-logger/Kconfig
@@ -0,0 +1,6 @@
+# Copyright 2020 Daniel Friesel
+#
+# SPDX-License-Identifier: CC0-1.0
+
+prompt "BME680 + MAX44009 data logger"
+depends on loop && !wakeup && meta_driver_i2c && driver_max44009 && driver_bme680
diff --git a/src/app/bme680-max44009-logger/Makefile.inc b/src/app/bme680-max44009-logger/Makefile.inc
index 98b37fe..33d05b0 100644
--- a/src/app/bme680-max44009-logger/Makefile.inc
+++ b/src/app/bme680-max44009-logger/Makefile.inc
@@ -12,4 +12,10 @@ ifdef app
COMMON_FLAGS += -DCONFIG_driver_bme680 -DCONFIG_driver_max44009
endif
-COMMON_FLAGS += -DBME680_FLOAT_POINT_COMPENSATION
+ifdef CONFIG_arch_posix
+ CXX_TARGETS += src/app/${app_dir}/posix.cc
+else
+ CXX_TARGETS += src/app/${app_dir}/generic.cc
+ COMMON_FLAGS += -DBME680_FLOAT_POINT_COMPENSATION
+endif
+
diff --git a/src/app/bme680-max44009-logger/generic.cc b/src/app/bme680-max44009-logger/generic.cc
new file mode 100644
index 0000000..34f785d
--- /dev/null
+++ b/src/app/bme680-max44009-logger/generic.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2022 Daniel Friesel
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include "arch.h"
+#include "driver/gpio.h"
+#include "driver/stdout.h"
+#if defined(CONFIG_meta_driver_hardware_i2c)
+#include "driver/i2c.h"
+#else
+#include "driver/soft_i2c.h"
+#endif
+#include "driver/bme680.h"
+#include "driver/bme680_util.h"
+#include "driver/max44009.h"
+
+#ifdef MULTIPASS_ARCH_arduino_nano
+#define POWER_PIN GPIO::pc3
+#endif
+
+struct bme680_field_data data;
+float lux;
+int8_t bme680_status;
+
+static void bme680_init(void)
+{
+ bme680_status = bme680.init();
+ kout << "# BME680 init returned " << bme680_status << endl;
+
+ bme680.power_mode = BME680_FORCED_MODE;
+ bme680.tph_sett.os_hum = BME680_OS_2X;
+ bme680.tph_sett.os_pres = BME680_OS_16X;
+ bme680.tph_sett.os_temp = BME680_OS_2X;
+
+ bme680.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
+ bme680.gas_sett.heatr_dur = 100;
+ bme680.gas_sett.heatr_temp = 300;
+ bme680.setSensorSettings(BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL);
+}
+
+void loop(void)
+{
+ static unsigned char i = 0;
+
+ if (lux >= 0 && bme680_status == 0) {
+ gpio.led_off(0);
+ } else {
+ gpio.led_on(0);
+ }
+
+#ifdef POWER_PIN
+ if (lux < 0 || bme680_status != 0) {
+ if (i == 17) {
+ kout << "# Cycling power to I2C clients" << endl;
+ gpio.write(POWER_PIN, 0);
+ } else if (i == 18) {
+ gpio.write(POWER_PIN, 1);
+ } else if (i == 19) {
+ bme680_init();
+ }
+ }
+#endif
+
+#ifdef MULTIPASS_ARCH_arduino_nano
+ if ((i == 1) && (ADCSRA & _BV(ADIF))) {
+ uint8_t adcr_l = ADCL;
+ uint8_t adcr_h = ADCH;
+ uint16_t adcr = adcr_l + (adcr_h << 8);
+ uint16_t vcc = 1100L * 1023 / adcr;
+
+ TIFR1 |= _BV(TOV1);
+ ADCSRA |= _BV(ADIF);
+
+ kout << "VCC: " << vcc << endl;
+ }
+#endif
+
+ if (i == 0) {
+ lux = max44009.getLux();
+ if (lux >= 0) {
+ kout << "MAX44009: ";
+ kout.printf_float(max44009.getLux());
+ kout << " lx" << endl;
+ } else {
+ kout << "# MAX44009 error" << endl;
+ }
+ }
+
+ if (i == 1 && bme680_status == 0) {
+ bme680_status = bme680.setSensorMode();
+ }
+ else if (i == 2) {
+ if (bme680_status == 0) {
+ bme680_status = bme680.getSensorData(&data);
+ }
+ if (bme680_status == 0) {
+ bme680.amb_temp = data.temperature;
+ kout << "BME680 temperature: " << data.temperature << " degC" << endl;
+ kout << "BME680 humidity: " << data.humidity << " %" << endl;
+ kout << "BME680 pressure: " << data.pressure / 100 << " hPa" << endl;
+ kout << "BME680 gas resistance: " << data.gas_resistance << endl;
+ } else {
+ kout << "# BME680 error " << bme680_status << endl;
+ }
+ }
+
+ i = (i + 1) % 20;
+}
+
+int main(void)
+{
+ arch.setup();
+ gpio.setup();
+ kout.setup();
+
+#ifdef POWER_PIN
+ gpio.output(POWER_PIN);
+ gpio.write(POWER_PIN, 1);
+#endif
+
+#ifdef MULTIPASS_ARCH_arduino_nano
+
+ kout << "# Reset reason: " << MCUSR << endl;
+ MCUSR = 0;
+
+ /* watchdog reset after ~4 seconds */
+ asm("wdr");
+ WDTCSR = _BV(WDCE) | _BV(WDE);
+ WDTCSR = _BV(WDE) | _BV(WDP3);
+
+ // One ADC conversion per four seconds
+ TCCR0A = 0;
+ TCCR0B = _BV(CS12) | _BV(CS10);
+
+ // Measure internal 1.1V bandgap using VCC as reference on each Timer 0 overflow
+ ADMUX = _BV(REFS0) | 0x0e;
+ ADCSRB = _BV(ADTS2);
+ ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADPS2) | _BV(ADPS1);
+#endif
+
+ while (i2c.setup() != 0) {
+ kout << "# I2C setup failed" << endl;
+ arch.delay_ms(100);
+ }
+
+ kout << "# I2C setup OK" << endl;
+
+ bme680.intf = BME680_I2C_INTF;
+ bme680.read = bme680_i2c_read;
+ bme680.write = bme680_i2c_write;
+ bme680.delay_ms = bme680_delay_ms;
+
+ bme680.amb_temp = 25;
+
+ bme680_init();
+
+ arch.idle_loop();
+
+ return 0;
+}
diff --git a/src/app/bme680-max44009-logger/main.cc b/src/app/bme680-max44009-logger/main.cc
index 8a3ce3a..27b2ebf 100644
--- a/src/app/bme680-max44009-logger/main.cc
+++ b/src/app/bme680-max44009-logger/main.cc
@@ -1,161 +1,9 @@
/*
- * Copyright 2021 Daniel Friesel
+ * Copyright 2022 Daniel Friesel
*
- * SPDX-License-Identifier: BSD-2-Clause
+ * SPDX-License-Identifier: CC0-1.0
*/
-#include "arch.h"
-#include "driver/gpio.h"
-#include "driver/stdout.h"
-#if defined(CONFIG_meta_driver_hardware_i2c)
-#include "driver/i2c.h"
-#else
-#include "driver/soft_i2c.h"
-#endif
-#include "driver/bme680.h"
-#include "driver/bme680_util.h"
-#include "driver/max44009.h"
-#ifdef MULTIPASS_ARCH_arduino_nano
-#define POWER_PIN GPIO::pc3
-#endif
-
-struct bme680_field_data data;
-float lux;
-int8_t bme680_status;
-
-static void bme680_init(void)
-{
- bme680_status = bme680.init();
- kout << "# BME680 init returned " << bme680_status << endl;
-
- bme680.power_mode = BME680_FORCED_MODE;
- bme680.tph_sett.os_hum = BME680_OS_2X;
- bme680.tph_sett.os_pres = BME680_OS_16X;
- bme680.tph_sett.os_temp = BME680_OS_2X;
-
- bme680.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
- bme680.gas_sett.heatr_dur = 100;
- bme680.gas_sett.heatr_temp = 300;
- bme680.setSensorSettings(BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL);
-}
-
-void loop(void)
-{
- static unsigned char i = 0;
-
- if (lux >= 0 && bme680_status == 0) {
- gpio.led_off(0);
- } else {
- gpio.led_on(0);
- }
-
-#ifdef POWER_PIN
- if (lux < 0 || bme680_status != 0) {
- if (i == 17) {
- kout << "# Cycling power to I2C clients" << endl;
- gpio.write(POWER_PIN, 0);
- } else if (i == 18) {
- gpio.write(POWER_PIN, 1);
- } else if (i == 19) {
- bme680_init();
- }
- }
-#endif
-
-#ifdef MULTIPASS_ARCH_arduino_nano
- if ((i == 1) && (ADCSRA & _BV(ADIF))) {
- uint8_t adcr_l = ADCL;
- uint8_t adcr_h = ADCH;
- uint16_t adcr = adcr_l + (adcr_h << 8);
- uint16_t vcc = 1100L * 1023 / adcr;
-
- TIFR1 |= _BV(TOV1);
- ADCSRA |= _BV(ADIF);
-
- kout << "VCC: " << vcc << endl;
- }
-#endif
-
- if (i == 0) {
- lux = max44009.getLux();
- if (lux >= 0) {
- kout << "MAX44009: ";
- kout.printf_float(max44009.getLux());
- kout << " lx" << endl;
- } else {
- kout << "# MAX44009 error" << endl;
- }
- }
-
- if (i == 1 && bme680_status == 0) {
- bme680_status = bme680.setSensorMode();
- }
- else if (i == 2) {
- if (bme680_status == 0) {
- bme680_status = bme680.getSensorData(&data);
- }
- if (bme680_status == 0) {
- bme680.amb_temp = data.temperature;
- kout << "BME680 temperature: " << data.temperature << " degC" << endl;
- kout << "BME680 humidity: " << data.humidity << " %" << endl;
- kout << "BME680 pressure: " << data.pressure / 100 << " hPa" << endl;
- kout << "BME680 gas resistance: " << data.gas_resistance << endl;
- } else {
- kout << "# BME680 error " << bme680_status << endl;
- }
- }
-
- i = (i + 1) % 20;
-}
-
-int main(void)
-{
- arch.setup();
- gpio.setup();
- kout.setup();
-
-#ifdef POWER_PIN
- gpio.output(POWER_PIN);
- gpio.write(POWER_PIN, 1);
-#endif
-
-#ifdef MULTIPASS_ARCH_arduino_nano
-
- kout << "# Reset reason: " << MCUSR << endl;
- MCUSR = 0;
-
- /* watchdog reset after ~4 seconds */
- asm("wdr");
- WDTCSR = _BV(WDCE) | _BV(WDE);
- WDTCSR = _BV(WDE) | _BV(WDP3);
-
- // One ADC conversion per four seconds
- TCCR0A = 0;
- TCCR0B = _BV(CS12) | _BV(CS10);
-
- // Measure internal 1.1V bandgap using VCC as reference on each Timer 0 overflow
- ADMUX = _BV(REFS0) | 0x0e;
- ADCSRB = _BV(ADTS2);
- ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADPS2) | _BV(ADPS1);
-#endif
-
- while (i2c.setup() != 0) {
- kout << "# I2C setup failed" << endl;
- arch.delay_ms(100);
- }
-
- kout << "# I2C setup OK" << endl;
-
- bme680.intf = BME680_I2C_INTF;
- bme680.read = bme680_i2c_read;
- bme680.write = bme680_i2c_write;
- bme680.delay_ms = bme680_delay_ms;
-
- bme680.amb_temp = 25;
-
- bme680_init();
-
- arch.idle_loop();
-
- return 0;
-}
+/*
+ * Intentionally left blank.
+ */
diff --git a/src/app/bme680-max44009-logger/posix.cc b/src/app/bme680-max44009-logger/posix.cc
new file mode 100644
index 0000000..4086f79
--- /dev/null
+++ b/src/app/bme680-max44009-logger/posix.cc
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2022 Daniel Friesel
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "config.h"
+#ifdef CONFIG_driver_bme680_bsec_save_state
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define BSEC_STATE_PATH TOSTRING(CONFIG_driver_bme680_bsec_state_path)
+#include <stdio.h>
+#endif
+
+#include "arch.h"
+#include "driver/gpio.h"
+#include "driver/stdout.h"
+#include "driver/uptime.h"
+#if defined(CONFIG_meta_driver_hardware_i2c)
+#include "driver/i2c.h"
+#else
+#include "driver/soft_i2c.h"
+#endif
+#include "driver/bme680.h"
+#include "driver/bme680_util.h"
+#include "driver/bme680-bsec-armv6/bsec_interface.h"
+#include "driver/max44009.h"
+
+bsec_bme_settings_t sensor_settings;
+
+void load_bsec_state()
+{
+ uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE];
+ uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
+ FILE *f = fopen(BSEC_STATE_PATH, "r");
+ if (f != NULL) {
+ size_t serialized_state_size = fread(serialized_state, BSEC_MAX_STATE_BLOB_SIZE, sizeof(uint8_t), f);
+ if (serialized_state_size > 0) {
+ bsec_library_return_t bsec_status = bsec_set_state(serialized_state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, BSEC_MAX_STATE_BLOB_SIZE);
+ if (bsec_status < 0) {
+ kout << "# bsec_set_state error: " << bsec_status << endl;
+ }
+ if (bsec_status > 0) {
+ kout << "# bsec_set_state warning: " << bsec_status << endl;
+ }
+ }
+ if (fclose(f) == EOF) {
+ perror("fclose");
+ }
+ } else {
+ // file doesn't exist. that's harmless.
+ perror("fopen");
+ }
+}
+
+void save_bsec_state()
+{
+ uint32_t serialized_state_size;
+ uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE];
+ uint8_t work_buffer[BSEC_MAX_STATE_BLOB_SIZE];
+
+ bsec_library_return_t status = bsec_get_state(0, serialized_state, BSEC_MAX_STATE_BLOB_SIZE, work_buffer, BSEC_MAX_STATE_BLOB_SIZE, &serialized_state_size);
+ if (status < 0) {
+ kout << "# bsec_get_state error: " << status << endl;
+ return;
+ }
+ if (status > 0) {
+ kout << "# bsec_get_state warning: " << status << endl;
+ }
+ FILE *f = fopen(BSEC_STATE_PATH, "w");
+ if (f == NULL) {
+ perror("fopen");
+ return;
+ }
+ if (fwrite(serialized_state, sizeof(uint8_t), serialized_state_size, f) < serialized_state_size) {
+ perror("fwrite");
+ }
+ if (fclose(f) == EOF) {
+ perror("fclose");
+ }
+}
+
+int configure_bsec()
+{
+ bsec_sensor_configuration_t virtual_sensors[8];
+ unsigned char n_virtual_sensors = 8;
+
+ bsec_sensor_configuration_t sensor_configs[BSEC_MAX_PHYSICAL_SENSOR];
+ unsigned char n_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
+
+ float sample_rate = BSEC_SAMPLE_RATE_LP;
+
+ virtual_sensors[0].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
+ virtual_sensors[0].sample_rate = sample_rate;
+ virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
+ virtual_sensors[1].sample_rate = sample_rate;
+ virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
+ virtual_sensors[2].sample_rate = sample_rate;
+ virtual_sensors[3].sensor_id = BSEC_OUTPUT_RAW_GAS;
+ virtual_sensors[3].sample_rate = sample_rate;
+ virtual_sensors[4].sensor_id = BSEC_OUTPUT_IAQ;
+ virtual_sensors[4].sample_rate = sample_rate;
+ virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
+ virtual_sensors[5].sample_rate = sample_rate;
+ virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
+ virtual_sensors[6].sample_rate = sample_rate;
+ virtual_sensors[7].sensor_id = BSEC_OUTPUT_STATIC_IAQ;
+ virtual_sensors[7].sample_rate = sample_rate;
+
+ bsec_library_return_t bsec_status = bsec_update_subscription(virtual_sensors, n_virtual_sensors, sensor_configs, &n_sensor_settings);
+
+ if (bsec_status != BSEC_OK) {
+ kout << "# bsec_update_subscription error: " << bsec_status << endl;
+ return 1;
+ }
+ kout << "# bsec_update_subscription OK" << endl;
+ return 0;
+}
+
+void control_bsec(int64_t now)
+{
+ struct bme680_field_data data;
+ bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
+ bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
+
+ uint8_t num_bsec_inputs = 0;
+ uint8_t num_bsec_outputs = BSEC_NUMBER_OUTPUTS;
+
+ bsec_library_return_t status = bsec_sensor_control(now, &sensor_settings);
+
+ if (status < 0) {
+ kout << "# bsec_sensor_control error: " << status << endl;
+ return;
+ }
+ if (status > 0) {
+ kout << "# bsec_sensor_control warning: " << status << endl;
+ }
+
+ if (!sensor_settings.trigger_measurement) {
+ return;
+ }
+
+ bme680.tph_sett.os_hum = sensor_settings.humidity_oversampling;
+ bme680.tph_sett.os_pres = sensor_settings.pressure_oversampling;
+ bme680.tph_sett.os_temp = sensor_settings.temperature_oversampling;
+ bme680.gas_sett.run_gas = sensor_settings.run_gas;
+ bme680.gas_sett.heatr_temp = sensor_settings.heater_temperature;
+ bme680.gas_sett.heatr_dur = sensor_settings.heating_duration;
+
+ bme680.power_mode = BME680_FORCED_MODE;
+ bme680.setSensorSettings(BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL);
+
+ bme680.setSensorMode();
+
+
+ /*
+ * TODO recent versions of the bme680 open-source driver are able to
+ * calculate the required delay.
+ */
+ arch.delay_ms(250);
+
+ do {
+ arch.delay_ms(5);
+ bme680.getSensorMode();
+ } while (bme680.power_mode == BME680_FORCED_MODE);
+
+ if (sensor_settings.process_data) {
+ bme680.getSensorData(&data);
+ if (data.status & BME680_NEW_DATA_MSK) {
+ if (sensor_settings.process_data & BSEC_PROCESS_TEMPERATURE) {
+ bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
+ bsec_inputs[num_bsec_inputs].signal = data.temperature / 100.0f;
+ bsec_inputs[num_bsec_inputs].time_stamp = now;
+ num_bsec_inputs++;
+ }
+ if (sensor_settings.process_data & BSEC_PROCESS_HUMIDITY) {
+ bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
+ bsec_inputs[num_bsec_inputs].signal = data.humidity / 1000.0f;
+ bsec_inputs[num_bsec_inputs].time_stamp = now;
+ num_bsec_inputs++;
+ }
+ if (sensor_settings.process_data & BSEC_PROCESS_PRESSURE) {
+ bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
+ bsec_inputs[num_bsec_inputs].signal = data.pressure;
+ bsec_inputs[num_bsec_inputs].time_stamp = now;
+ num_bsec_inputs++;
+ }
+ if (sensor_settings.process_data & BSEC_PROCESS_GAS) {
+ bsec_inputs[num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
+ bsec_inputs[num_bsec_inputs].signal = data.gas_resistance;
+ bsec_inputs[num_bsec_inputs].time_stamp = now;
+ num_bsec_inputs++;
+ }
+ }
+ }
+
+ if (num_bsec_inputs > 0) {
+ status = bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);
+
+ if (status < 0) {
+ kout << "# bsec_do_steps error: " << status << endl;
+ return;
+ }
+ if (status > 0) {
+ kout << "# bsec_do_steps warning: " << status << endl;
+ }
+
+ kout << "bme680 ";
+ for (uint8_t i = 0; i < num_bsec_outputs; i++) {
+ if (i > 0) {
+ kout << ",";
+ }
+ switch (bsec_outputs[i].sensor_id) {
+ case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
+ kout << "temperature_celsius=" << bsec_outputs[i].signal;
+ break;
+ case BSEC_OUTPUT_RAW_TEMPERATURE:
+ kout << "raw_temperature_celsius=" << bsec_outputs[i].signal;
+ break;
+ case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
+ kout << "humidity_relpercent=" << bsec_outputs[i].signal;
+ break;
+ case BSEC_OUTPUT_RAW_HUMIDITY:
+ kout << "raw_humidity_relpercent=" << bsec_outputs[i].signal;
+ break;
+ case BSEC_OUTPUT_RAW_PRESSURE:
+ kout << "pressure_hpa=" << bsec_outputs[i].signal / 100;
+ break;
+ case BSEC_OUTPUT_RAW_GAS:
+ kout << "air_quality_ohm=" << bsec_outputs[i].signal;
+ break;
+ case BSEC_OUTPUT_IAQ:
+ if (bsec_outputs[i].accuracy > 0) {
+ kout << "air_quality_index=" << bsec_outputs[i].signal << ",";
+ }
+ kout << "air_quality_accuracy_index=" << bsec_outputs[i].accuracy;
+ break;
+ case BSEC_OUTPUT_STATIC_IAQ:
+ kout << "air_quality_raw=" << bsec_outputs[i].signal;
+ break;
+ default:
+ continue;
+ }
+ }
+ kout << endl;
+ }
+}
+
+void loop(void)
+{
+ static uint16_t i = 0;
+ int64_t now = uptime.get_us() * 1000;
+
+ if ((now < sensor_settings.next_call) && (sensor_settings.next_call - now < 1000000000)) {
+ // less than one second -> sleep
+ arch.delay_us((sensor_settings.next_call - now) / 1000);
+ now = uptime.get_us() * 1000;
+ }
+
+ if (now >= sensor_settings.next_call) {
+ control_bsec(now);
+ }
+
+ if ((i%20) == 0) {
+ float lux = max44009.getLux();
+ if (lux >= 0) {
+ kout << "max44009 illuminance_lux=" << max44009.getLux() << endl;
+ } else {
+ kout << "# MAX44009 error" << endl;
+ }
+ }
+
+ if ((i%1800) == 0) {
+ save_bsec_state();
+ }
+
+ i++;
+}
+
+int main(void)
+{
+ arch.setup();
+ gpio.setup();
+ kout.setup();
+
+ while (i2c.setup() != 0) {
+ kout << "# I2C setup failed" << endl;
+ return 1;
+ }
+ kout << "# I2C setup OK" << endl;
+
+ bme680.intf = BME680_I2C_INTF;
+ bme680.read = bme680_i2c_read;
+ bme680.write = bme680_i2c_write;
+ bme680.delay_ms = bme680_delay_ms;
+
+ int8_t bme680_status = bme680.init();
+ while (bme680_status != 0) {
+ kout << "# BME680 init failed: " << (uint8_t)bme680_status << endl;
+ return 1;
+ }
+ kout << "# BME680 init OK" << endl;
+
+ bsec_library_return_t bsec_status = bsec_init();
+ while (bsec_status != BSEC_OK) {
+ kout << "# BSEC init failed: " << bsec_status << endl;
+ return 1;
+ }
+ kout << "# BSEC init OK" << endl;
+
+ load_bsec_state();
+
+ if (configure_bsec() != 0) {
+ return 1;
+ }
+
+ arch.idle_loop();
+
+ return 0;
+}