From b538e605321791568aa25f0bd534ebcb30da92c2 Mon Sep 17 00:00:00 2001
From: Joel Spadin <joelspadin@gmail.com>
Date: Sat, 24 Oct 2020 13:39:02 -0500
Subject: [PATCH] feat(endpoints): update on BLE profile change

Added zmk_ble_active_profile_is_connected() to allow code outside ble.c to check
the status of the active profile, and changed the ble_active_profile_changed
event to also notify when the active profile connects or disconnects.

Changed endpoint selection to to also update when the active profile changes,
connects, or disconnects.
---
 app/include/zmk/ble.h |  1 +
 app/src/ble.c         | 26 +++++++++++++++++++++++---
 app/src/endpoints.c   | 24 ++++++++++++++++++------
 3 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h
index 1cf71a77..56980c69 100644
--- a/app/include/zmk/ble.h
+++ b/app/include/zmk/ble.h
@@ -15,6 +15,7 @@ int zmk_ble_prof_prev();
 int zmk_ble_prof_select(u8_t index);
 
 bt_addr_le_t *zmk_ble_active_profile_addr();
+bool zmk_ble_active_profile_is_connected();
 char *zmk_ble_active_profile_name();
 
 int zmk_ble_unpair_all();
diff --git a/app/src/ble.c b/app/src/ble.c
index 9090582c..a79f7237 100644
--- a/app/src/ble.c
+++ b/app/src/ble.c
@@ -94,6 +94,12 @@ static void raise_profile_changed_event() {
     ZMK_EVENT_RAISE(ev);
 }
 
+static void raise_profile_changed_event_callback(struct k_work *work) {
+    raise_profile_changed_event();
+}
+
+K_WORK_DEFINE(raise_profile_changed_event_work, raise_profile_changed_event_callback);
+
 static bool active_profile_is_open() {
     return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY);
 }
@@ -111,7 +117,7 @@ void set_profile_address(u8_t index, const bt_addr_le_t *addr) {
     raise_profile_changed_event();
 }
 
-bool active_profile_is_connected() {
+bool zmk_ble_active_profile_is_connected() {
     struct bt_conn *conn;
     bt_addr_le_t *addr = zmk_ble_active_profile_addr();
     if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
@@ -163,9 +169,9 @@ int update_advertising() {
     struct bt_conn *conn;
     enum advertising_type desired_adv = ZMK_ADV_NONE;
 
-    if (active_profile_is_open() || !active_profile_is_connected()) {
+    if (active_profile_is_open() || !zmk_ble_active_profile_is_connected()) {
         desired_adv = ZMK_ADV_CONN;
-    } else if (!active_profile_is_connected()) {
+    } else if (!zmk_ble_active_profile_is_connected()) {
         desired_adv = ZMK_ADV_CONN;
         // Need to fix directed advertising for privacy centrals. See
         // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char
@@ -327,6 +333,10 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
 struct settings_handler profiles_handler = {.name = "ble", .h_set = ble_profiles_handle_set};
 #endif /* IS_ENABLED(CONFIG_SETTINGS) */
 
+static bool is_conn_active_profile(const struct bt_conn *conn) {
+    return bt_addr_le_cmp(bt_conn_get_dst(conn), &profiles[active_profile].peer) == 0;
+}
+
 static void connected(struct bt_conn *conn, u8_t err) {
     char addr[BT_ADDR_LE_STR_LEN];
     bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
@@ -352,6 +362,11 @@ static void connected(struct bt_conn *conn, u8_t err) {
     }
 
     update_advertising();
+
+    if (is_conn_active_profile(conn)) {
+        LOG_DBG("Active profile connected");
+        raise_profile_changed_event();
+    }
 }
 
 static void disconnected(struct bt_conn *conn, u8_t reason) {
@@ -364,6 +379,11 @@ static void disconnected(struct bt_conn *conn, u8_t reason) {
     // We need to do this in a work callback, otherwise the advertising update will still see the
     // connection for a profile as active, and not start advertising yet.
     k_work_submit(&update_advertising_work);
+
+    if (is_conn_active_profile(conn)) {
+        LOG_DBG("Active profile disconnected");
+        k_work_submit(&raise_profile_changed_event_work);
+    }
 }
 
 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
diff --git a/app/src/endpoints.c b/app/src/endpoints.c
index 3acaba64..56204a47 100644
--- a/app/src/endpoints.c
+++ b/app/src/endpoints.c
@@ -4,11 +4,13 @@
  * SPDX-License-Identifier: MIT
  */
 
+#include <zmk/ble.h>
 #include <zmk/endpoints.h>
 #include <zmk/hid.h>
 #include <zmk/usb.h>
 #include <zmk/hog.h>
 #include <zmk/event-manager.h>
+#include <zmk/events/ble-active-profile-changed.h>
 #include <zmk/events/usb-conn-state-changed.h>
 
 #include <logging/log.h>
@@ -19,8 +21,9 @@ enum endpoint {
     ENDPOINT_BLE,
 };
 
-static enum endpoint current_endpoint =
-    COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB));
+#define DEFAULT_ENDPOINT COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB))
+
+static enum endpoint current_endpoint = DEFAULT_ENDPOINT;
 
 static int send_keypad_report() {
     struct zmk_hid_keypad_report *keypad_report = zmk_hid_get_keypad_report();
@@ -115,15 +118,22 @@ static bool is_ble_ready() {
 static enum endpoint get_selected_endpoint() {
     if (is_ble_ready()) {
         if (is_usb_ready()) {
-            LOG_DBG("Both endpoints ready. Selecting USB");
+            LOG_DBG("Both endpoints are ready.");
             // TODO: add user setting to control this
             return ENDPOINT_USB;
         }
 
+        LOG_DBG("Only BLE is ready.");
         return ENDPOINT_BLE;
     }
 
-    return ENDPOINT_USB;
+    if (is_usb_ready()) {
+        LOG_DBG("Only USB is ready.");
+        return ENDPOINT_USB;
+    }
+
+    LOG_DBG("No endpoints are ready.");
+    return DEFAULT_ENDPOINT;
 }
 
 static void disconnect_current_endpoint() {
@@ -149,7 +159,9 @@ static int endpoint_listener(const struct zmk_event_header *eh) {
 }
 
 ZMK_LISTENER(endpoint_listener, endpoint_listener);
-#if IS_ENABLED(CONFIG_USB)
+#if IS_ENABLED(CONFIG_ZMK_USB)
 ZMK_SUBSCRIPTION(endpoint_listener, usb_conn_state_changed);
 #endif
-// TODO: add BLE state subscription
\ No newline at end of file
+#if IS_ENABLED(CONFIG_ZMK_BLE)
+ZMK_SUBSCRIPTION(endpoint_listener, ble_active_profile_changed);
+#endif
\ No newline at end of file