From 25fc893968b1755fb94882650645e54ad73b4f7c Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sat, 27 Jul 2019 01:32:41 +0200
Subject: [PATCH] feat(bhi160): Initial Python support for the accelerometer

---
 epicardium/epicardium.h          |  5 ++-
 epicardium/modules/bhi.c         |  4 +++
 pycardium/meson.build            |  1 +
 pycardium/modules/bhi160-sys.c   | 61 ++++++++++++++++++++++++++++++++
 pycardium/modules/interrupt.c    |  2 ++
 pycardium/modules/py/bhi160.py   | 38 ++++++++++++++++++++
 pycardium/modules/py/meson.build |  1 +
 pycardium/modules/qstrdefs.h     |  7 +++-
 pycardium/mpconfigport.h         |  1 +
 9 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 pycardium/modules/bhi160-sys.c
 create mode 100644 pycardium/modules/py/bhi160.py

diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 930eb876..56158107 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -156,9 +156,12 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));
 #define EPIC_INT_UART_RX                2
 /** RTC Alarm interrupt.  See :c:func:`epic_isr_rtc_alarm` */
 #define EPIC_INT_RTC_ALARM              3
+/** TODO: BHI */
+#define EPIC_INT_BHI160_ACCELEROMETER   4
+API_ISR(EPIC_INT_BHI160_ACCELEROMETER, epic_isr_bhi160_accelerometer);
 
 /* Number of defined interrupts. */
-#define EPIC_INT_NUM                    4
+#define EPIC_INT_NUM                    5
 /* clang-format on */
 
 /*
diff --git a/epicardium/modules/bhi.c b/epicardium/modules/bhi.c
index 5e05e672..e824f70d 100644
--- a/epicardium/modules/bhi.c
+++ b/epicardium/modules/bhi.c
@@ -11,6 +11,7 @@
 #include "semphr.h"
 #include "queue.h"
 
+#include "api/interrupt-sender.h"
 #include "epicardium.h"
 #include "modules/log.h"
 #include "modules/modules.h"
@@ -211,6 +212,9 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
 			&data_vector,
 			BHI160_MUTEX_WAIT_MS
 		);
+		if (sensor_id == VS_ID_ACCELEROMETER_WAKEUP) {
+			api_interrupt_trigger(EPIC_INT_BHI160_ACCELEROMETER);
+		}
 		break;
 	default:
 		break;
diff --git a/pycardium/meson.build b/pycardium/meson.build
index f0a3798a..2c43f62f 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -1,6 +1,7 @@
 name = 'pycardium'
 
 modsrc = files(
+  'modules/bhi160-sys.c',
   'modules/buttons.c',
   'modules/fat_file.c',
   'modules/fat_reader_import.c',
diff --git a/pycardium/modules/bhi160-sys.c b/pycardium/modules/bhi160-sys.c
new file mode 100644
index 00000000..35d81b25
--- /dev/null
+++ b/pycardium/modules/bhi160-sys.c
@@ -0,0 +1,61 @@
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/builtin.h"
+#include "epicardium.h"
+#include "api/common.h"
+#include "mphalport.h"
+
+STATIC mp_obj_t mp_bhi160_enable_sensor(size_t n_args, const mp_obj_t *args)
+{
+	int sensor_type = mp_obj_get_int(args[0]);
+
+	struct bhi160_sensor_config cfg = { 0 };
+	cfg.sample_buffer_len           = mp_obj_get_int(args[1]);
+	cfg.sample_rate                 = mp_obj_get_int(args[2]);
+	cfg.dynamic_range               = mp_obj_get_int(args[3]);
+
+	//cfg.sample_buffer_len = 200;
+	//cfg.sample_rate       = 4;
+	//cfg.dynamic_range     = 2;
+
+	int sd = epic_bhi160_enable_sensor(sensor_type, &cfg);
+
+	return MP_OBJ_NEW_SMALL_INT(sd);
+}
+
+STATIC mp_obj_t mp_bhi160_read_sensor(mp_obj_t stream_id_in)
+{
+	struct bhi160_data_vector buf[100];
+	int sd = mp_obj_get_int(stream_id_in);
+
+	int n = epic_stream_read(sd, buf, sizeof(buf));
+
+	return MP_OBJ_NEW_SMALL_INT(n);
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
+	mp_bhi160_enable_sensor_obj, 4, 4, mp_bhi160_enable_sensor
+);
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(
+	mp_bhi160_read_sensor_obj, mp_bhi160_read_sensor
+);
+
+STATIC const mp_rom_map_elem_t bhi160_module_globals_table[] = {
+	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys_bhi160) },
+	{ MP_ROM_QSTR(MP_QSTR_enable_sensor),
+	  MP_ROM_PTR(&mp_bhi160_enable_sensor_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_read_sensor),
+	  MP_ROM_PTR(&mp_bhi160_read_sensor_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(bhi160_module_globals, bhi160_module_globals_table);
+
+// Define module object.
+const mp_obj_module_t bhi160_module = {
+	.base    = { &mp_type_module },
+	.globals = (mp_obj_dict_t *)&bhi160_module_globals,
+};
+
+/* clang-format off */
+// Register the module to make it available in Python
+MP_REGISTER_MODULE(MP_QSTR_sys_bhi160, bhi160_module, MODULE_BHI160_ENABLED);
diff --git a/pycardium/modules/interrupt.c b/pycardium/modules/interrupt.c
index 10770a19..90dd700a 100644
--- a/pycardium/modules/interrupt.c
+++ b/pycardium/modules/interrupt.c
@@ -85,6 +85,8 @@ static const mp_rom_map_elem_t interrupt_module_globals_table[] = {
 	/* Interrupt Numbers */
 	{ MP_ROM_QSTR(MP_QSTR_RTC_ALARM),
 	  MP_OBJ_NEW_SMALL_INT(EPIC_INT_RTC_ALARM) },
+	{ MP_ROM_QSTR(MP_QSTR_BHI160_ACCELEROMETER),
+	  MP_OBJ_NEW_SMALL_INT(EPIC_INT_BHI160_ACCELEROMETER) },
 };
 static MP_DEFINE_CONST_DICT(
 	interrupt_module_globals, interrupt_module_globals_table
diff --git a/pycardium/modules/py/bhi160.py b/pycardium/modules/py/bhi160.py
new file mode 100644
index 00000000..4d13895f
--- /dev/null
+++ b/pycardium/modules/py/bhi160.py
@@ -0,0 +1,38 @@
+import sys_bhi160
+import interrupt
+
+
+class BHI160Accelerometer:
+    def __init__(
+        self, sample_rate=4, dynamic_range=2, callback=None, sample_buffer_len=200
+    ):
+        interrupt.disable_callback(interrupt.BHI160_ACCELEROMETER)
+        interrupt.set_callback(
+            interrupt.BHI160_ACCELEROMETER, self._accelerometer_interrupt
+        )
+        self.acc_sd = sys_bhi160.enable_sensor(
+            0, sample_buffer_len, sample_rate, dynamic_range
+        )
+        self._callback = callback
+        if callback:
+            interrupt.enable_callback(interrupt.BHI160_ACCELEROMETER)
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, _et, _ev, _t):
+        self.close()
+
+    def close(self):
+        if self.acc_sd is not None:
+            self.acc_sd = None
+            self.acc_sd = sys_bhi160.disable_sensor(0)
+            interrupt.disable_callback(interrupt.BHI160_ACCELEROMETER)
+            interrupt.set_callback(interrupt.BHI160_ACCELEROMETER, None)
+
+    def _accelerometer_interrupt(self, _):
+        if self.acc_sd is not None:
+            data = sys_bhi160.read_sensor(self.acc_sd)
+            print(data)
+            if self._callback:
+                self._callback(data)
diff --git a/pycardium/modules/py/meson.build b/pycardium/modules/py/meson.build
index 2818ffa3..9bd34944 100644
--- a/pycardium/modules/py/meson.build
+++ b/pycardium/modules/py/meson.build
@@ -1,4 +1,5 @@
 python_modules = files(
+  'bhi160.py',
   'color.py',
   'htmlcolor.py',
   'display.py',
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 60c5c56c..4d9ff17a 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -57,9 +57,14 @@ Q(vibrate)
 Q(set_callback)
 Q(enable_callback)
 Q(disable_callback)
-Q(BHI160)
+Q(BHI160_ACCELEROMETER)
 Q(RTC_ALARM)
 
+/* bhi160 */
+Q(sys_bhi160)
+Q(enable_sensor)
+Q(read_sensor)
+
 /* display */
 Q(sys_display)
 Q(display)
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index af27e146..b8486798 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -45,6 +45,7 @@ int mp_hal_trng_read_int(void);
 #define MICROPY_PY_UERRNO                   (1)
 
 /* Modules */
+#define MODULE_BHI160_ENABLED               (1)
 #define MODULE_BME680_ENABLED               (1)
 #define MODULE_BUTTONS_ENABLED              (1)
 #define MODULE_DISPLAY_ENABLED              (1)
-- 
GitLab