From 8db3c3ace351f742407828ddc6d15cb2ee5d8c0b Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sat, 2 May 2020 20:49:06 +0200
Subject: [PATCH] feat(bsec): Initial BSEC API

---
 epicardium/epicardium.h   | 117 ++++++++++++++++++++++++++++++++++++++
 epicardium/modules/bsec.c |  17 ++++++
 2 files changed, 134 insertions(+)

diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 3a2fea1a..d8161824 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -128,6 +128,7 @@ typedef _Bool bool;
 #define API_BME680_INIT            0xD0
 #define API_BME680_DEINIT          0xD1
 #define API_BME680_GET_DATA        0xD2
+#define API_BSEC_GET_DATA          0xD3
 
 #define API_BHI160_ENABLE          0xe0
 #define API_BHI160_DISABLE         0xe1
@@ -918,6 +919,122 @@ API(API_BME680_GET_DATA, int epic_bme680_read_sensors(
 	struct bme680_sensor_data *data
 ));
 
+/**
+ * BME680 Sensor Data
+ */
+struct bsec_sensor_data {
+	/** Compensated temperature in degree celsius */
+	float temperature;
+	/** Compensated humidity in % relative humidity */
+	float humidity;
+	/** Pressure in hPa */
+	float pressure;
+	/** Gas resistance in Ohms */
+	float gas_resistance;
+	/** Timestamp in of the measurement in UNIX time (seconds since
+	 * 1970-01-01 00:00:00 UTC)*/
+	uint32_t timestamp;
+	/** Accuracy of IAQ, CO2 equivalent and breath VOC equivalent:
+	 * 0: Stabilization / run-in ongoing:
+	 *    This means that the sensor still needs to warm up. Takes about
+	 *    5 min after activation of BSEC / reboot.
+	 *
+	 * 1: Low accuracy:
+	 *    The sensor has not yet been calibrated. BSEC needs to collect
+	 *    more data to calibrate the sensor. This can take multiple
+	 *    hours.
+	 *
+	 *    BSEC documentation: To reach high accuracy(3) please expose
+	 *    sensor once to good air (e.g. outdoor air) and bad air (e.g.
+	 *    box with exhaled breath) for auto-trimming
+	 *
+	 * 2: Medium accuracy: auto-trimming ongoing
+	 *    BSEC has detected that it needs to recalibrate the sensor.
+	 *    This is an automatic process and usally finishes after tens
+	 *    of minutes. Can happen every now and then.
+	 *
+	 * 3: High accuracy:
+	 *    The sensor has warmed up and is calibrated.
+	 *
+	 * From BSEC documentation:
+	 * IAQ accuracy indicator will notify the user when they should
+	 * initiate a calibration process. Calibration is performed automatically
+	 * in the background if the sensor is exposed to clean and polluted air
+	 * for approximately 30 minutes each.
+	 *
+	 * See also:
+	 * https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BME680-IAQ-accuracy-definition/m-p/5931/highlight/true#M10
+	 */
+	uint8_t accuracy;
+	/** Indoor Air Quality with range 0 to 500
+	 *
+	 * Statement from the Bosch BSEC library:
+	 *
+	 * Indoor-air-quality (IAQ) gives an indication of the relative change
+	 * in ambient TVOCs detected by BME680.
+	 *
+	 * The IAQ scale ranges from 0 (clean air) to 500 (heavily polluted air).
+	 * During operation, algorithms automatically calibrate and adapt
+	 * themselves to the typical environments where the sensor is operated
+	 * (e.g., home, workplace, inside a car, etc.).This automatic background
+	 * calibration ensures that users experience consistent IAQ performance.
+	 * The calibration process considers the recent measurement history (typ.
+	 * up to four days) to ensure that IAQ=25 corresponds to typical good air
+	 * and IAQ=250 indicates typical polluted air.
+	 *
+	 * Please also consult the BME680 datsheet (pages 9 and 21) as well:
+	 * https://git.card10.badge.events.ccc.de/card10/hardware/-/blob/master/datasheets/bosch/BST-BME680-DS001.pdf
+	 *
+	 */
+	int32_t indoor_air_quality;
+	/** Unscaled IAQ value.
+	 *
+	 * See this post for details:
+	 * https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BME680-strange-IAQ-and-CO2-values/m-p/9667/highlight/true#M1505
+	 */
+	int32_t static_indoor_air_quality;
+	/** Estimation of equivalant CO2 content in the air in ppm. */
+	float co2_equivalent;
+	/** Estimation of equivalant brath VOC content in the air in ppm. */
+	float breath_voc_equivalent;
+};
+
+/**
+ * Get the current BME680 data filtered by Bosch BSEC library
+ *
+ * The Bosch BSEC libary allows to compute an indoor air
+ * qualtiy (IAQ)metric as well as CO2 and VOC content
+ * equivalents using the gas sensor of the BME680.
+ *
+ * The sample rate is currently fixed to one sample every 3 seconds.
+ * Querying the sensor more often will return cached data.
+ *
+ * After the libary has been activated it starts to calibrate the
+ * sensor. This can take multiple hours.
+ * After a reset/power on it takes about 5 minutes to stabilize
+ * the sensor if it was calibrated before.
+ *
+ * The BSEC library regularly recalibrates the sensor during operation.
+ * The ``accuracy`` field of the return data indicates the calibration
+ * status of the sensor. Please take it into consideration when
+ * using / displaying the IAQ.
+ *
+ * Please refer to the description of ``bsec_sensor_data`` for more
+ * information about how to interpret its content.
+ *
+ * .. versionadded:: 1.
+ *
+ * :param data: Where to store the environmental data.
+ * :return: 0 on success or ``-Exxx`` on error.  The following
+ *     errors might occur:
+ *
+ *     - ``-EFAULT``:  On NULL-pointer.
+ *     - ``-EINVAL``:  No data available from the sensor.
+ *     - ``-ENODEV``:  BSEC libray is not running.
+ */
+API(API_BSEC_GET_DATA, int epic_bsec_read_sensors(
+	struct bsec_sensor_data *data
+));
 /**
  * MAX86150
  * ======
diff --git a/epicardium/modules/bsec.c b/epicardium/modules/bsec.c
index bcb81bd6..e257708a 100644
--- a/epicardium/modules/bsec.c
+++ b/epicardium/modules/bsec.c
@@ -132,6 +132,23 @@ void output_ready(
 	       (unsigned int)(breath_voc_equivalent * 1e3));
 }
 
+int epic_bsec_read_sensors(struct bsec_sensor_data *data)
+{
+	if(data == NULL) {
+		return -EFAULT;
+	}
+	if(!bsec_task_active) {
+		return -ENODEV;
+	}
+
+	/* TODO: could also return -EINVAL */
+	while (last_bme680_timestamp == 0)
+		vTaskDelay(pdMS_TO_TICKS(10));
+
+	*data = last_bsec_data;
+	return 0;
+}
+
 static uint32_t bsec_load(char *path, uint8_t *buffer, uint32_t n_buffer)
 {
 	uint32_t len = 0;
-- 
GitLab