From a44bc26e21d4a536b11fa39e8d32029fa91fd7cf Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Wed, 29 Apr 2020 22:18:10 +0200
Subject: [PATCH] fix(bsec): Reduce stack usage by calling init before stating
 the task

---
 epicardium/main.c            | 20 ++++-----
 epicardium/modules/bsec.c    | 78 +++++++++++++++++++++++-------------
 epicardium/modules/modules.h |  1 +
 3 files changed, 62 insertions(+), 37 deletions(-)

diff --git a/epicardium/main.c b/epicardium/main.c
index b9631e45..4e2cba12 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -126,15 +126,17 @@ int main(void)
 	}
 
 	/* BSEC */
-	if (xTaskCreate(
-		    vBSECTask,
-		    (const char *)"BSEC",
-		    configMINIMAL_STACK_SIZE * 4,
-		    NULL,
-		    tskIDLE_PRIORITY + 1,
-		    NULL) != pdPASS) {
-		LOG_CRIT("startup", "Failed to create %s task!", "BSEC");
-		abort();
+	if(bsec_activate() == 0) {
+		if (xTaskCreate(
+				vBSECTask,
+				(const char *)"BSEC",
+				configMINIMAL_STACK_SIZE * 3, /* 768 bytes. Mainly for state saving... */
+				NULL,
+				tskIDLE_PRIORITY + 1,
+				NULL) != pdPASS) {
+			LOG_CRIT("startup", "Failed to create %s task!", "BSEC");
+			abort();
+		}
 	}
 
 	/* API */
diff --git a/epicardium/modules/bsec.c b/epicardium/modules/bsec.c
index abda8a79..08306dd3 100644
--- a/epicardium/modules/bsec.c
+++ b/epicardium/modules/bsec.c
@@ -20,7 +20,7 @@
 TaskHandle_t bsec_task_id;
 static struct bme680_sensor_data last_bme680_data;
 static int64_t last_bme680_timestamp;
-static bool active;
+static bool bsec_task_active;
 #define ULP 0
 
 // From generic_18v_3s_4d/bsec_serialized_configurations_iaq.c
@@ -227,6 +227,17 @@ static int8_t i2c_read(uint8_t addr, uint8_t reg, uint8_t *p_buf, uint16_t size)
 	return ret;
 }
 
+static void delay(uint32_t msec)
+{
+	if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
+		/* We need to fall back to hardware waits if not running
+		 * in a task context */
+		card10_bosch_delay(msec);
+	} else {
+		vTaskDelay(pdMS_TO_TICKS(msec));
+	}
+}
+
 /*!
  * @brief           Load library config from non-volatile memory
  *
@@ -280,19 +291,14 @@ void ulp_plus_trigger_iaq()
 }
 #endif
 
-static void delay(uint32_t msec)
-{
-	vTaskDelay(pdMS_TO_TICKS(msec));
-}
-
 bool bsec_active(void)
 {
-	return active;
+	return bsec_task_active;
 }
 
 int bsec_read_bme680(struct bme680_sensor_data *data)
 {
-	if (!active) {
+	if (!bsec_task_active) {
 		return BME680_E_COM_FAIL;
 	}
 	while (last_bme680_timestamp == 0)
@@ -301,46 +307,62 @@ int bsec_read_bme680(struct bme680_sensor_data *data)
 	return BME680_OK;
 }
 
-void vBSECTask(void *pvParameters)
+/**
+ * Checks config and activates the BSEC libary if requested.
+ *
+ * Initializes the BSEC library before starting the task to
+ * reduce the stack size needed for the task by at least 512 bytes
+ */
+int bsec_activate(void)
 {
 	return_values_init ret;
-	active       = true;
-	bsec_task_id = xTaskGetCurrentTaskHandle();
-
 #if ULP
 	float sample_rate = BSEC_SAMPLE_RATE_ULP;
-	/* State is saved every 100 samples, which means every 100 * 300 secs = 500 minutes  */
-	const int stat_save_interval = 100;
 #else
 	float sample_rate = BSEC_SAMPLE_RATE_LP;
-	/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes  */
-	const int stat_save_interval = 10000;
 #endif
 
 	float temperature_offset = 0.0;
-	ret                      = bsec_iot_init(
-                sample_rate,
-                temperature_offset,
-                i2c_write,
-                i2c_read,
-                delay,
-                state_load,
-                config_load
+
+	/* Puts AT LEAST 2 * #BSEC_MAX_PROPERTY_BLOB_SIZE = 2 * 454 = 908 bytes onto the stack */
+	ret = bsec_iot_init(
+		sample_rate,
+		temperature_offset,
+		i2c_write,
+		i2c_read,
+		delay,
+		state_load,
+		config_load
 	);
 
 	if (ret.bme680_status) {
 		printf("bme680 init failed\n");
 		/* Could not intialize BME680 */
-		while (1)
-			;
+		return -1;
 	} else if (ret.bsec_status) {
 		printf("bsec init failed\n");
 		/* Could not intialize BSEC library */
-		while (1)
-			;
+		return -1;
 	}
+	return 0;
+}
+
+void vBSECTask(void *pvParameters)
+{
+	bsec_task_active = true;
+	bsec_task_id     = xTaskGetCurrentTaskHandle();
+
+#if ULP
+	/* State is saved every 100 samples, which means every 100 * 300 secs = 500 minutes  */
+	const int stat_save_interval = 100;
+#else
+	/* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes  */
+	const int stat_save_interval = 10000;
+#endif
 
 	/* Call to endless loop function which reads and processes data based on sensor settings */
+	/* Puts AT LEAST 2 * BSEC_MAX_STATE_BLOB_SIZE + 8 * sizeof(bsec_input_t) =
+	 * 2 * 139 + 8 * 20 = 438 bytes onto the stack */
 	bsec_iot_loop(
 		delay,
 		get_timestamp_us,
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index 1d962550..a1aab4c4 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -137,6 +137,7 @@ void max30001_mutex_init(void);
 extern gpio_cfg_t gpio_configs[];
 
 /* ---------- BSEC / BME680 ------------------------------------------------ */
+int bsec_activate(void);
 void vBSECTask(void *pvParameters);
 bool bsec_active(void);
 struct bme680_sensor_data;
-- 
GitLab