From cd1191ddf934b7837b80b6964997dbab80c156a0 Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Tue, 16 Jun 2020 00:30:09 +0200
Subject: [PATCH] feat(ble): Allow apps to make the device bondable

---
 epicardium/ble/ble_main.c     | 67 +++++++++++++++++++++++++++++++----
 epicardium/epicardium.h       | 14 +++++---
 epicardium/modules/hardware.c |  5 +++
 pycardium/modules/qstrdefs.h  |  2 ++
 pycardium/modules/sys_ble.c   | 36 +++++++++++++++----
 5 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c
index 72fd05696..5b10d7915 100644
--- a/epicardium/ble/ble_main.c
+++ b/epicardium/ble/ble_main.c
@@ -43,6 +43,9 @@
 #include "api/interrupt-sender.h"
 #include "modules/log.h"
 
+static bool active;
+static uint32_t ble_event;
+
 /**************************************************************************************************
   Macros
 **************************************************************************************************/
@@ -360,6 +363,30 @@ static void bleSetup(bleMsg_t *pMsg)
   } else {
     AppAdvStart(APP_MODE_CONNECTABLE);
   }
+  active = true;
+}
+
+void epic_ble_set_bondable(bool bondable)
+{
+	if(!active) {
+		return;
+	}
+
+	if(bondable) {
+		LOG_INFO("ble", "Making bondable and discoverable");
+		/* We need to stop advertising in between or the
+		 * adv set will not be changed... */
+		AppAdvStop();
+		AppSetBondable(TRUE);
+		AppAdvStart(APP_MODE_DISCOVERABLE);
+	} else {
+		LOG_INFO("ble", "Making connectable");
+		AppAdvStop();
+		AppSetBondable(FALSE);
+		if(AppDbCheckBonded()) {
+			AppAdvStart(APP_MODE_CONNECTABLE);
+		}
+	}
 }
 
 uint32_t epic_ble_get_compare_value(void)
@@ -367,22 +394,48 @@ uint32_t epic_ble_get_compare_value(void)
 	return pair_confirm_value;
 }
 
-void epic_ble_confirm_compare_value(void)
+void epic_ble_compare_response(bool confirmed)
 {
+	if(!active) {
+		return;
+	}
+
 	if(pair_connId != DM_CONN_ID_NONE) {
-		LOG_INFO("ble", "Confirming");
-		DmSecCompareRsp(pair_connId, TRUE);
+		LOG_INFO("ble", "Value confirmed: %u", confirmed);
+		DmSecCompareRsp(pair_connId, confirmed);
 	} else {
-		//TODO: error condition
+		/* error condition */
 	}
 }
+static void trigger_event(uint32_t event)
+{
+	bool enabled;
+	epic_interrupt_is_enabled(EPIC_INT_BLE, &enabled);
+	if(ble_event & enabled) {
+		LOG_WARN("ble", "Application missed event %lu", ble_event);
+	}
 
-void bleHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd)
+	ble_event = event;
+	api_interrupt_trigger(EPIC_INT_BLE);
+}
+
+uint32_t epic_ble_get_event(void)
 {
+	uint32_t event = ble_event;
+	ble_event = 0;
+	return event;
+}
+
+static void bleHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd)
+{
+	if(!active) {
+		return;
+	}
+
 	pair_connId = (dmConnId_t)pCnfInd->hdr.param;
 	pair_confirm_value = DmSecGetCompareValue(pCnfInd->confirm);
 	LOG_INFO("ble", "Confirm Value: %ld", pair_confirm_value);
-	api_interrupt_trigger(EPIC_INT_BLE_NUMERIC_COMPARISON);
+	trigger_event(1);
 }
 
 /*************************************************************************************************/
@@ -478,6 +531,7 @@ static void bleProcMsg(bleMsg_t *pMsg)
       uiEvent = APP_UI_SEC_PAIR_CMPL;
       /* After a successful pairing, bonding is disabled again.
        * We don't want that for now. */
+      trigger_event(3);
       AppSetBondable(TRUE);
       break;
 
@@ -498,6 +552,7 @@ static void bleProcMsg(bleMsg_t *pMsg)
       }
       pair_connId = DM_CONN_ID_NONE;
       uiEvent = APP_UI_SEC_PAIR_FAIL;
+      trigger_event(2);
       break;
 
     case DM_SEC_ENCRYPT_IND:
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 790d84eea..c41f3ce4e 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -148,8 +148,10 @@ typedef _Bool bool;
 #define API_CONFIG_GET_BOOLEAN     0x132
 #define API_CONFIG_SET_STRING      0x133
 
-#define API_BLE_GET_COMPARE_VALUE 0x140
-#define API_BLE_CONFIRM_COMPARE_VALUE 0x141
+#define API_BLE_GET_COMPARE_VALUE  0x140
+#define API_BLE_COMPARE_RESPONSE   0x141
+#define API_BLE_SET_BONDABLE       0x142
+#define API_BLE_GET_EVENT          0x143
 
 /* clang-format on */
 
@@ -216,7 +218,7 @@ API(API_INTERRUPT_IS_ENABLED, int epic_interrupt_is_enabled(api_int_id_t int_id,
 /** MAX86150 ECG and PPG sensor.  See :c:func:`epic_isr_max86150`. */
 #define EPIC_INT_MAX86150		9
 
-#define EPIC_INT_BLE_NUMERIC_COMPARISON 10
+#define EPIC_INT_BLE                    10
 /* Number of defined interrupts. */
 #define EPIC_INT_NUM                    11
 /* clang-format on */
@@ -2090,7 +2092,9 @@ API(API_CONFIG_GET_STRING, int epic_config_get_string(const char *key, char *buf
 API(API_CONFIG_SET_STRING, int epic_config_set_string(const char *key, const char *value));
 
 API(API_BLE_GET_COMPARE_VALUE, uint32_t epic_ble_get_compare_value(void));
-API(API_BLE_CONFIRM_COMPARE_VALUE, void epic_ble_confirm_compare_value(void));
-API_ISR(EPIC_INT_BLE_NUMERIC_COMPARISON, epic_isr_ble_numeric_comparison);
+API(API_BLE_COMPARE_RESPONSE, void epic_ble_compare_response(bool confirmed));
+API(API_BLE_SET_BONDABLE, void epic_ble_set_bondable(bool bondable));
+API(API_BLE_GET_EVENT, uint32_t epic_ble_get_event(void));
+API_ISR(EPIC_INT_BLE, epic_isr_ble);
 #endif /* _EPICARDIUM_H */
 
diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c
index 6d118fe73..1168f5a75 100644
--- a/epicardium/modules/hardware.c
+++ b/epicardium/modules/hardware.c
@@ -289,5 +289,10 @@ int hardware_reset(void)
 
 	epic_max86150_disable_sensor();
 
+	/*
+	 * BLE
+	 */
+	epic_ble_set_bondable(false);
+
 	return 0;
 }
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 589dcafd0..1010817a5 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -196,4 +196,6 @@ Q(get_string)
 Q(ble)
 Q(get_compare_value)
 Q(confirm_compare_value)
+Q(set_bondable)
+Q(get_event)
 
diff --git a/pycardium/modules/sys_ble.c b/pycardium/modules/sys_ble.c
index 856db7567..7da5ca32d 100644
--- a/pycardium/modules/sys_ble.c
+++ b/pycardium/modules/sys_ble.c
@@ -6,23 +6,47 @@
 
 #include <stdint.h>
 
-static mp_obj_t mp_ble_confirm_compare_value(void)
+static mp_obj_t mp_ble_confirm_compare_value(mp_obj_t confirmed_obj)
 {
-	epic_ble_confirm_compare_value();
+	bool confirmed = mp_obj_is_true(confirmed_obj);
+	epic_ble_compare_response(confirmed);
 	return mp_const_none;
 }
-static MP_DEFINE_CONST_FUN_OBJ_0(ble_confirm_compare_value_obj, mp_ble_confirm_compare_value);
+static MP_DEFINE_CONST_FUN_OBJ_1(
+	ble_confirm_compare_value_obj, mp_ble_confirm_compare_value
+);
 
 static mp_obj_t mp_ble_get_compare_value(void)
 {
 	return mp_obj_new_int(epic_ble_get_compare_value());
 }
-static MP_DEFINE_CONST_FUN_OBJ_0(ble_get_compare_value_obj, mp_ble_get_compare_value);
+static MP_DEFINE_CONST_FUN_OBJ_0(
+	ble_get_compare_value_obj, mp_ble_get_compare_value
+);
+
+static mp_obj_t mp_ble_get_event(void)
+{
+	return mp_obj_new_int(epic_ble_get_event());
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(ble_get_event_obj, mp_ble_get_event);
+
+static mp_obj_t mp_ble_set_bondable(mp_obj_t bondable_obj)
+{
+	bool bondable = mp_obj_is_true(bondable_obj);
+	epic_ble_set_bondable(bondable);
+	return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_1(ble_set_bondable_obj, mp_ble_set_bondable);
 
 static const mp_rom_map_elem_t ble_module_globals_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys_ble) },
-	{ MP_ROM_QSTR(MP_QSTR_confirm_compare_value), MP_ROM_PTR(&ble_confirm_compare_value_obj) },
-	{ MP_ROM_QSTR(MP_QSTR_get_compare_value), MP_ROM_PTR(&ble_get_compare_value_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_confirm_compare_value),
+	  MP_ROM_PTR(&ble_confirm_compare_value_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_get_compare_value),
+	  MP_ROM_PTR(&ble_get_compare_value_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_get_event), MP_ROM_PTR(&ble_get_event_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_set_bondable),
+	  MP_ROM_PTR(&ble_set_bondable_obj) },
 };
 static MP_DEFINE_CONST_DICT(ble_module_globals, ble_module_globals_table);
 
-- 
GitLab