From 23b4a9ed8be7ad25197acc4557dfe1c530b49e67 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Sun, 29 Dec 2019 11:41:19 +0100
Subject: [PATCH] fix(bhi160): Disable driver on critical error

If initialization fails, bhi160 API calls should not infinitely block
waiting for it to complete; they should fail immediately with an error
stating that something went wrong.

Add a flag that indicates the driver to not accept API requests because
initialization was not finished properly.

Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/FreeRTOSConfig.h |  1 +
 epicardium/modules/bhi.c    | 40 +++++++++++++++++++++++++++++++++----
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/epicardium/FreeRTOSConfig.h b/epicardium/FreeRTOSConfig.h
index 22c6dfb0..8ff4a4b4 100644
--- a/epicardium/FreeRTOSConfig.h
+++ b/epicardium/FreeRTOSConfig.h
@@ -50,6 +50,7 @@
 
 #define INCLUDE_vTaskSuspend        1
 #define INCLUDE_vTaskDelay          1
+#define INCLUDE_vTaskDelete         1
 #define INCLUDE_uxTaskGetStackHighWaterMark 1
 #define INCLUDE_xTimerPendFunctionCall 1
 #define INCLUDE_xSemaphoreGetMutexHolder 1
diff --git a/epicardium/modules/bhi.c b/epicardium/modules/bhi.c
index 3ef515b8..c767a8cc 100644
--- a/epicardium/modules/bhi.c
+++ b/epicardium/modules/bhi.c
@@ -61,6 +61,13 @@ static struct stream_info bhi160_streams[10];
 /* Active */
 static bool bhi160_sensor_active[10] = { 0 };
 
+/*
+ * Driver State:  A flag that is set when an unrecoverable error occurred.
+ * Effectively, this means the sensor will be disabled until next reboot and any
+ * API calls will fail immediately.
+ */
+static bool bhi160_driver_b0rked = false;
+
 /* -- Utilities -------------------------------------------------------- {{{ */
 /*
  * Retrieve the data size for a sensor.  This value is needed for the creation
@@ -133,6 +140,11 @@ int epic_bhi160_enable_sensor(
 	mutex_lock(&bhi160_mutex);
 	hwlock_acquire(HWLOCK_I2C);
 
+	if (bhi160_driver_b0rked) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
 	struct stream_info *stream = &bhi160_streams[sensor_type];
 	stream->item_size          = bhi160_lookup_data_size(sensor_type);
 	/* TODO: Sanity check length */
@@ -183,6 +195,11 @@ int epic_bhi160_disable_sensor(enum bhi160_sensor_type sensor_type)
 	mutex_lock(&bhi160_mutex);
 	hwlock_acquire(HWLOCK_I2C);
 
+	if (bhi160_driver_b0rked) {
+		result = -ENODEV;
+		goto out_free;
+	}
+
 	struct stream_info *stream = &bhi160_streams[sensor_type];
 	result = stream_deregister(bhi160_lookup_sd(sensor_type), stream);
 	if (result < 0) {
@@ -384,7 +401,7 @@ static void bhi160_interrupt_callback(void *_)
 {
 	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
-	if (bhi160_task_id != NULL) {
+	if (bhi160_task_id != NULL && !bhi160_driver_b0rked) {
 		vTaskNotifyGiveFromISR(
 			bhi160_task_id, &xHigherPriorityTaskWoken
 		);
@@ -428,13 +445,28 @@ void vBhi160Task(void *pvParameters)
 	/* Upload firmware */
 	ret = bhy_driver_init(bhy1_fw);
 	if (ret) {
-		LOG_CRIT("bhi160", "BHy1 init failed!");
-		vTaskDelay(portMAX_DELAY);
+		LOG_CRIT("bhi160", "BHy1 init failed!  Disabling.");
+
+		/* Disable BHI160 until next reboot */
+		bhi160_driver_b0rked = true;
+		hwlock_release(HWLOCK_I2C);
+		mutex_unlock(&bhi160_mutex);
+		vTaskDelete(NULL);
 	}
 
 	/* Wait for first interrupt, a falling edge */
 	hwlock_release(HWLOCK_I2C);
-	ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
+	if (ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(2000)) == 0) {
+		LOG_CRIT(
+			"bhi160",
+			"Sensor firmware was not loaded correctly.  Disabling."
+		);
+
+		/* Disable BHI160 until next reboot */
+		bhi160_driver_b0rked = true;
+		mutex_unlock(&bhi160_mutex);
+		vTaskDelete(NULL);
+	}
 	hwlock_acquire(HWLOCK_I2C);
 
 	/*
-- 
GitLab