From 43e05fc9d549a1aeba191b6e74d1d694d1a6d992 Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sun, 26 Apr 2020 01:09:22 +0200
Subject: [PATCH] feat(spo2): Add Maxim RD117 pycardium interface

---
 pycardium/meson.build         |  1 +
 pycardium/modules/qstrdefs.h  |  3 ++
 pycardium/modules/spo2_algo.c | 83 +++++++++++++++++++++++++++++++++++
 pycardium/mpconfigport.h      |  1 +
 4 files changed, 88 insertions(+)
 create mode 100644 pycardium/modules/spo2_algo.c

diff --git a/pycardium/meson.build b/pycardium/meson.build
index d983ab7bb..2bfb09d31 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -15,6 +15,7 @@ modsrc = files(
   'modules/os.c',
   'modules/personal_state.c',
   'modules/power.c',
+  'modules/spo2_algo.c',
   'modules/sys_ble.c',
   'modules/sys_bme680.c',
   'modules/sys_display.c',
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index b145dc118..f842f5344 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -212,3 +212,6 @@ Q(EVENT_PAIRING_COMPLETE)
 Q(EVENT_PAIRING_FAILED)
 Q(EVENT_SCAN_REPORT)
 
+/* SpO2 */
+Q(spo2_algo)
+Q(maxim_rd117)
diff --git a/pycardium/modules/spo2_algo.c b/pycardium/modules/spo2_algo.c
new file mode 100644
index 000000000..c10ae6386
--- /dev/null
+++ b/pycardium/modules/spo2_algo.c
@@ -0,0 +1,83 @@
+#include "epicardium.h"
+
+#include "RD117_MBED/algorithm/algorithm.h"
+#include "py/builtin.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+static mp_obj_t
+mp_maxim_rd177(mp_obj_t ir, mp_obj_t red)
+{
+	uint32_t pun_ir_buffer[500];
+	uint32_t pun_red_buffer[500];
+	int32_t n_ir_buffer_length;
+
+	int32_t pn_spo2 = 0;
+	int8_t pch_spo2_valid = 0;
+	int32_t pn_heart_rate = 0;
+	int8_t pch_hr_valid = 0;
+
+	size_t ir_len;
+	mp_obj_t *ir_elem;
+	mp_obj_get_array(ir, &ir_len, &ir_elem);
+
+	if (ir_len < 100 || ir_len > 500) {
+		nlr_raise(mp_obj_new_exception_msg_varg(
+			&mp_type_TypeError,
+			"rd177 needs a tuple of length 100 to 500 (%d given)",
+			ir_len)
+		);
+	}
+
+	size_t red_len;
+	mp_obj_t *red_elem;
+	mp_obj_get_array(red, &red_len, &red_elem);
+
+	if (red_len != ir_len) {
+		nlr_raise(mp_obj_new_exception_msg_varg(
+			&mp_type_TypeError,
+			"Length of ir and red data needs to be equal")
+		);
+	}
+
+	n_ir_buffer_length = ir_len;
+	for(size_t i=0; i<ir_len; i++) {
+		pun_ir_buffer[i] = mp_obj_get_int(ir_elem[i]);
+		pun_red_buffer[i] = mp_obj_get_int(red_elem[i]);
+	}
+
+	maxim_heart_rate_and_oxygen_saturation(pun_ir_buffer, n_ir_buffer_length, pun_red_buffer, &pn_spo2, &pch_spo2_valid, &pn_heart_rate, &pch_hr_valid);
+
+	mp_obj_t spo2 = mp_obj_new_int(pn_spo2);
+	mp_obj_t hr = mp_obj_new_int(pn_heart_rate);
+	mp_obj_t spo2_valid = mp_obj_new_int(pch_spo2_valid);
+	mp_obj_t hr_valid = mp_obj_new_int(pch_hr_valid);
+
+	mp_obj_t tup[] = {
+		spo2,
+		spo2_valid,
+		hr,
+		hr_valid
+	};
+
+	return mp_obj_new_tuple(4, tup);
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(maxim_rd117, mp_maxim_rd177);
+
+static const mp_rom_map_elem_t spo2_algo_module_globals_table[] = {
+	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spo2_algo) },
+	{ MP_ROM_QSTR(MP_QSTR_maxim_rd117), MP_ROM_PTR(&maxim_rd117) },
+};
+static MP_DEFINE_CONST_DICT(
+	spo2_algo_module_globals, spo2_algo_module_globals_table
+);
+
+// Define module object.
+const mp_obj_module_t spo2_algo_module = {
+	.base    = { &mp_type_module },
+	.globals = (mp_obj_dict_t *)&spo2_algo_module_globals,
+};
+
+/* Register the module to make it available in Python */
+/* clang-format off */
+MP_REGISTER_MODULE(MP_QSTR_spo2_algo, spo2_algo_module, MODULE_SPO2_ALGO_ENABLED);
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index 4dd6aa129..c9f687ac4 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -68,6 +68,7 @@ int mp_hal_csprng_read_int(void);
 #define MODULE_OS_ENABLED                   (1)
 #define MODULE_PERSONAL_STATE_ENABLED       (1)
 #define MODULE_POWER_ENABLED                (1)
+#define MODULE_SPO2_ALGO_ENABLED            (1)
 #define MODULE_UTIME_ENABLED                (1)
 #define MODULE_VIBRA_ENABLED                (1)
 #define MODULE_WS2812_ENABLED               (1)
-- 
GitLab