summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorPete Johanson <peter@peterjohanson.com>2020-09-13 22:43:45 -0400
committerGitHub <noreply@github.com>2020-09-13 22:43:45 -0400
commit160f296bfb562ca0596630f84c4121920ea3c304 (patch)
tree63218f4af1b20108af667de8e346d204076064bb /app
parent304603240f7ba16f67912a0031c64fb9ae4e8279 (diff)
parent4658999e31865e54d02955c500c716385e6c69d8 (diff)
Merge pull request #133 from petejohanson/bluetooth/ident-management
feat(bluetooth): Proper basic bond management, new `bt` behavior for resetting bond to host.
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt26
-rw-r--r--app/Kconfig36
-rw-r--r--app/boards/shields/settings_reset/Kconfig.defconfig10
-rw-r--r--app/boards/shields/settings_reset/Kconfig.shield5
-rw-r--r--app/boards/shields/settings_reset/settings_reset.conf1
-rw-r--r--app/boards/shields/settings_reset/settings_reset.keymap22
-rw-r--r--app/boards/shields/settings_reset/settings_reset.overlay24
-rw-r--r--app/dts/behaviors.dtsi3
-rw-r--r--app/dts/behaviors/bluetooth.dtsi9
-rw-r--r--app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml8
-rw-r--r--app/include/dt-bindings/zmk/bt.h21
-rw-r--r--app/include/zmk/ble.h13
-rw-r--r--app/include/zmk/ble/profile.h16
-rw-r--r--app/include/zmk/events/ble-active-profile-changed.h22
-rw-r--r--app/src/behaviors/behavior_bt.c60
-rw-r--r--app/src/ble.c348
-rw-r--r--app/src/events/ble_active_profile_changed.c10
-rw-r--r--app/src/hog.c36
-rw-r--r--app/src/split/bluetooth/central.c40
-rw-r--r--app/src/split/bluetooth/service.c6
-rw-r--r--app/src/split_listener.c5
21 files changed, 649 insertions, 72 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 2e24fdc..3e0560b 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -29,22 +29,26 @@ target_sources(app PRIVATE src/hid.c)
target_sources(app PRIVATE src/sensors.c)
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c)
target_sources(app PRIVATE src/event_manager.c)
+target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
target_sources(app PRIVATE src/events/position_state_changed.c)
target_sources(app PRIVATE src/events/keycode_state_changed.c)
target_sources(app PRIVATE src/events/modifiers_state_changed.c)
target_sources(app PRIVATE src/events/sensor_event.c)
-target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
-target_sources(app PRIVATE src/behaviors/behavior_reset.c)
-target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
-target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
-target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
-target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
-target_sources(app PRIVATE src/behaviors/behavior_none.c)
-target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
-target_sources(app PRIVATE src/keymap.c)
+target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c)
+if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
+ target_sources(app PRIVATE src/behaviors/behavior_reset.c)
+ target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
+ target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
+ target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
+ target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
+ target_sources(app PRIVATE src/behaviors/behavior_none.c)
+ target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
+ target_sources(app PRIVATE src/keymap.c)
+endif()
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
+target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c)
-target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split_listener.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split/bluetooth/service.c)
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL app PRIVATE src/split/bluetooth/central.c)
@@ -57,4 +61,4 @@ target_sources(app PRIVATE src/endpoints.c)
target_sources(app PRIVATE src/hid_listener.c)
target_sources(app PRIVATE src/main.c)
-zephyr_cc_option(-Wfatal-errors) \ No newline at end of file
+zephyr_cc_option(-Wfatal-errors)
diff --git a/app/Kconfig b/app/Kconfig
index 877fce4..6180565 100644
--- a/app/Kconfig
+++ b/app/Kconfig
@@ -37,21 +37,26 @@ menuconfig ZMK_BLE
select BT
select BT_SMP
select BT_SMP_SC_PAIR_ONLY
+ select BT_SMP_APP_PAIRING_ACCEPT
select BT_PERIPHERAL
select BT_GATT_DIS
select BT_GATT_BAS
+ select BT_SETTINGS
select SETTINGS
- # select BT_SETTINGS
if ZMK_BLE
config ZMK_BLE_INIT_PRIORITY
int "Init Priority"
default 50
-
+
config SYSTEM_WORKQUEUE_STACK_SIZE
default 2048
+config ZMK_BLE_CLEAR_BONDS_ON_START
+ bool "Configuration that clears all bond information from the keyboard on startup."
+ default n
+
# HID GATT notifications sent this way are *not* picked up by Linux, and possibly others.
config BT_GATT_NOTIFY_MULTIPLE
default n
@@ -101,28 +106,20 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL
select BT_CENTRAL
select BT_GATT_CLIENT
-if ZMK_SPLIT_BLE_ROLE_CENTRAL
-
-config BT_MAX_CONN
- default 5
-
-config BT_MAX_PAIRED
- # Bump this everywhere once we support switching active connections!
- default 2
-
-endif
-
config ZMK_SPLIT_BLE_ROLE_PERIPHERAL
bool "Peripheral"
+ select BT_KEYS_OVERWRITE_OLDEST
if ZMK_SPLIT_BLE_ROLE_PERIPHERAL
config ZMK_USB
default n
+config BT_MAX_PAIRED
+ default 1
config BT_MAX_CONN
- default 5
+ default 1
config BT_GAP_AUTO_UPDATE_CONN_PARAMS
default n
@@ -135,8 +132,17 @@ endif
endif
-endmenu
+if ZMK_BLE && (!ZMK_SPLIT_BLE || ZMK_SPLIT_BLE_ROLE_CENTRAL)
+config BT_MAX_CONN
+ default 6
+
+config BT_MAX_PAIRED
+ default 5
+
+endif
+
+endmenu
config ZMK_KSCAN_MOCK_DRIVER
bool "Enable mock kscan driver to simulate key presses"
diff --git a/app/boards/shields/settings_reset/Kconfig.defconfig b/app/boards/shields/settings_reset/Kconfig.defconfig
new file mode 100644
index 0000000..6d050cb
--- /dev/null
+++ b/app/boards/shields/settings_reset/Kconfig.defconfig
@@ -0,0 +1,10 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if SHIELD_SETTINGS_RESET
+
+config ZMK_KEYBOARD_NAME
+ default "SETTINGS RESET"
+
+endif
+
diff --git a/app/boards/shields/settings_reset/Kconfig.shield b/app/boards/shields/settings_reset/Kconfig.shield
new file mode 100644
index 0000000..b5ce97f
--- /dev/null
+++ b/app/boards/shields/settings_reset/Kconfig.shield
@@ -0,0 +1,5 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+config SHIELD_SETTINGS_RESET
+ def_bool $(shields_list_contains,settings_reset)
diff --git a/app/boards/shields/settings_reset/settings_reset.conf b/app/boards/shields/settings_reset/settings_reset.conf
new file mode 100644
index 0000000..8052a6c
--- /dev/null
+++ b/app/boards/shields/settings_reset/settings_reset.conf
@@ -0,0 +1 @@
+CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START=y
diff --git a/app/boards/shields/settings_reset/settings_reset.keymap b/app/boards/shields/settings_reset/settings_reset.keymap
new file mode 100644
index 0000000..0523644
--- /dev/null
+++ b/app/boards/shields/settings_reset/settings_reset.keymap
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+
+/ {
+ keymap {
+ compatible = "zmk,keymap";
+
+ default_layer {
+ bindings = <
+ &reset
+ >;
+ };
+ };
+};
+
+
diff --git a/app/boards/shields/settings_reset/settings_reset.overlay b/app/boards/shields/settings_reset/settings_reset.overlay
new file mode 100644
index 0000000..a2b5799
--- /dev/null
+++ b/app/boards/shields/settings_reset/settings_reset.overlay
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ chosen {
+ zmk,kscan = &kscan0;
+ };
+
+ kscan0: kscan {
+ compatible = "zmk,kscan-gpio-direct";
+ label = "KSCAN";
+
+ input-gpios
+ = <&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+ ;
+ };
+
+};
+
diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi
index ab70bcc..202202b 100644
--- a/app/dts/behaviors.dtsi
+++ b/app/dts/behaviors.dtsi
@@ -7,4 +7,5 @@
#include <behaviors/toggle_layer.dtsi>
#include <behaviors/reset.dtsi>
#include <behaviors/sensor_rotate_key_press.dtsi>
-#include <behaviors/rgb_underglow.dtsi> \ No newline at end of file
+#include <behaviors/rgb_underglow.dtsi>
+#include <behaviors/bluetooth.dtsi> \ No newline at end of file
diff --git a/app/dts/behaviors/bluetooth.dtsi b/app/dts/behaviors/bluetooth.dtsi
new file mode 100644
index 0000000..ea09f4a
--- /dev/null
+++ b/app/dts/behaviors/bluetooth.dtsi
@@ -0,0 +1,9 @@
+/ {
+ behaviors {
+ bt: behavior_bluetooth {
+ compatible = "zmk,behavior-bluetooth";
+ label = "BLUETOOTH";
+ #binding-cells = <2>;
+ };
+ };
+};
diff --git a/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml
new file mode 100644
index 0000000..127ebe0
--- /dev/null
+++ b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml
@@ -0,0 +1,8 @@
+# Copyright (c) 2020, Peter Johanson
+# SPDX-License-Identifier: MIT
+
+description: Bluetooth Behavior
+
+compatible: "zmk,behavior-bluetooth"
+
+include: two_param.yaml
diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h
new file mode 100644
index 0000000..bf8b4f5
--- /dev/null
+++ b/app/include/dt-bindings/zmk/bt.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define BT_CLR_CMD 0
+#define BT_NXT_CMD 1
+#define BT_PRV_CMD 2
+#define BT_SEL_CMD 3
+// #define BT_FULL_RESET_CMD 4
+
+/*
+Note: Some future commands will include additional parameters, so we
+defines these aliases up front.
+*/
+
+#define BT_CLR BT_CLR_CMD 0
+#define BT_NXT BT_NXT_CMD 0
+#define BT_PRV BT_PRV_CMD 0
+#define BT_SEL BT_SEL_CMD \ No newline at end of file
diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h
index d0aaa96..1cf71a7 100644
--- a/app/include/zmk/ble.h
+++ b/app/include/zmk/ble.h
@@ -7,6 +7,19 @@
#pragma once
#include <zmk/keys.h>
+#include <zmk/ble/profile.h>
+
+int zmk_ble_clear_bonds();
+int zmk_ble_prof_next();
+int zmk_ble_prof_prev();
+int zmk_ble_prof_select(u8_t index);
+
+bt_addr_le_t *zmk_ble_active_profile_addr();
+char *zmk_ble_active_profile_name();
int zmk_ble_unpair_all();
bool zmk_ble_handle_key_user(struct zmk_key_event *key_event);
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr);
+#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ \ No newline at end of file
diff --git a/app/include/zmk/ble/profile.h b/app/include/zmk/ble/profile.h
new file mode 100644
index 0000000..9a79c6d
--- /dev/null
+++ b/app/include/zmk/ble/profile.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+#include <bluetooth/addr.h>
+
+#define ZMK_BLE_PROFILE_NAME_MAX 15
+
+struct zmk_ble_profile {
+ char name[ZMK_BLE_PROFILE_NAME_MAX];
+ bt_addr_le_t peer;
+};
diff --git a/app/include/zmk/events/ble-active-profile-changed.h b/app/include/zmk/events/ble-active-profile-changed.h
new file mode 100644
index 0000000..c464236
--- /dev/null
+++ b/app/include/zmk/events/ble-active-profile-changed.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#pragma once
+
+#include <zephyr.h>
+#include <zmk/event-manager.h>
+#include <device.h>
+
+#include <zmk/ble/profile.h>
+
+
+struct ble_active_profile_changed {
+ struct zmk_event_header header;
+ u8_t index;
+ struct zmk_ble_profile *profile;
+};
+
+ZMK_EVENT_DECLARE(ble_active_profile_changed);
diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c
new file mode 100644
index 0000000..3a5fbfb
--- /dev/null
+++ b/app/src/behaviors/behavior_bt.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define DT_DRV_COMPAT zmk_behavior_bluetooth
+
+#include <device.h>
+#include <drivers/behavior.h>
+
+#include <dt-bindings/zmk/bt.h>
+
+#include <bluetooth/conn.h>
+
+#include <logging/log.h>
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+#include <zmk/ble.h>
+
+static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg)
+{
+ switch (command)
+ {
+ case BT_CLR_CMD:
+ return zmk_ble_clear_bonds();
+ case BT_NXT_CMD:
+ return zmk_ble_prof_next();
+ case BT_PRV_CMD:
+ return zmk_ble_prof_prev();
+ case BT_SEL_CMD:
+ return zmk_ble_prof_select(arg);
+ default:
+ LOG_ERR("Unknown BT command: %d", command);
+ }
+
+ return -ENOTSUP;
+}
+
+static int behavior_bt_init(struct device *dev)
+{
+ return 0;
+};
+
+static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, u32_t arg)
+{
+ return 0;
+}
+
+static const struct behavior_driver_api behavior_bt_driver_api = {
+ .binding_pressed = on_keymap_binding_pressed,
+ .binding_released = on_keymap_binding_released,
+};
+
+DEVICE_AND_API_INIT(behavior_bt, DT_INST_LABEL(0),
+ behavior_bt_init,
+ NULL,
+ NULL,
+ APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
+ &behavior_bt_driver_api);
diff --git a/app/src/ble.c b/app/src/ble.c
index c4d3efd..a2a8207 100644
--- a/app/src/ble.c
+++ b/app/src/ble.c
@@ -8,6 +8,8 @@
#include <init.h>
#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <settings/settings.h>
#include <bluetooth/bluetooth.h>
@@ -15,33 +17,245 @@
#include <bluetooth/hci.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
+#include <bluetooth/hci_err.h>
+#if IS_ENABLED(CONFIG_SETTINGS)
+
+#include <settings/settings.h>
+
+#endif
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+#include <zmk/ble.h>
#include <zmk/keys.h>
#include <zmk/split/bluetooth/uuid.h>
+#include <zmk/event-manager.h>
+#include <zmk/events/ble-active-profile-changed.h>
static struct bt_conn *auth_passkey_entry_conn;
static u8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0};
static u8_t passkey_digit = 0;
-#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
-#define ZMK_ADV_PARAMS BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \
- BT_LE_ADV_OPT_USE_NAME | \
- BT_LE_ADV_OPT_ONE_TIME, \
- BT_GAP_ADV_FAST_INT_MIN_2, \
- BT_GAP_ADV_FAST_INT_MAX_2, NULL)
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
#else
-#define ZMK_ADV_PARAMS BT_LE_ADV_CONN_NAME
+#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
+#endif
+
+
+static struct zmk_ble_profile profiles[PROFILE_COUNT];
+static u8_t active_profile;
+
+static const struct bt_data zmk_ble_ad[] = {
+ BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+ BT_DATA_BYTES(BT_DATA_UUID16_SOME,
+#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ 0x12, 0x18, /* HID Service */
#endif
+ 0x0f, 0x18 /* Battery Service */
+ ),
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ BT_DATA_BYTES(BT_DATA_UUID128_ALL,
+ ZMK_SPLIT_BT_SERVICE_UUID)
+#endif
+};
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+
+static bt_addr_le_t peripheral_addr;
+
+#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
+
+static void raise_profile_changed_event()
+{
+ struct ble_active_profile_changed *ev = new_ble_active_profile_changed();
+ ev->index = active_profile;
+ ev->profile = &profiles[active_profile];
+
+ ZMK_EVENT_RAISE(ev);
+}
+
+static bool active_profile_is_open()
+{
+ return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY);
+}
+
+void set_profile_address(u8_t index, const bt_addr_le_t *addr)
+{
+ char setting_name[15];
+ char addr_str[BT_ADDR_LE_STR_LEN];
+
+ bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
+
+ memcpy(&profiles[index].peer, addr, sizeof(bt_addr_le_t));
+ sprintf(setting_name, "ble/profiles/%d", index);
+ LOG_DBG("Setting profile addr for %s to %s", log_strdup(setting_name), log_strdup(addr_str));
+ settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile));
+ raise_profile_changed_event();
+}
+
+int zmk_ble_adv_pause()
+{
+ int err = bt_le_adv_stop();
+ if (err) {
+ LOG_ERR("Failed to stop advertising (err %d)", err);
+ return err;
+ }
+
+ return 0;
+};
+
+int zmk_ble_adv_resume()
+{
+ LOG_DBG("active_profile %d, directed? %s", active_profile, active_profile_is_open() ? "no" : "yes");
+
+ int err = bt_le_adv_start(
+ BT_LE_ADV_CONN_NAME,
+ zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad),
+ NULL, 0);
+ if (err)
+ {
+ LOG_ERR("Advertising failed to start (err %d)", err);
+ return err;
+ }
+
+ return 0;
+};
+
+int zmk_ble_clear_bonds()
+{
+ LOG_DBG("");
+
+ if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) {
+ LOG_DBG("Unpairing!");
+ bt_unpair(BT_ID_DEFAULT, &profiles[active_profile].peer);
+ set_profile_address(active_profile, BT_ADDR_LE_ANY);
+ }
+
+ return 0;
+};
+
+int zmk_ble_prof_select(u8_t index)
+{
+ LOG_DBG("profile %d", index);
+ if (active_profile == index) {
+ return 0;
+ }
+
+ active_profile = index;
+ return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile));
+
+ raise_profile_changed_event();
+};
+
+int zmk_ble_prof_next()
+{
+ LOG_DBG("");
+ return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT);
+};
+
+int zmk_ble_prof_prev()
+{
+ LOG_DBG("");
+ return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT);
+};
+
+bt_addr_le_t *zmk_ble_active_profile_addr()
+{
+ return &profiles[active_profile].peer;
+}
+
+char *zmk_ble_active_profile_name()
+{
+ return profiles[active_profile].name;
+}
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+
+void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr)
+{
+ memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t));
+ settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t));
+}
+
+#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
+
+#if IS_ENABLED(CONFIG_SETTINGS)
+
+static int ble_profiles_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
+{
+ const char *next;
+
+ LOG_DBG("Setting BLE value %s", log_strdup(name));
+
+ if (settings_name_steq(name, "profiles", &next) && next) {
+ char *endptr;
+ u8_t idx = strtoul(next, &endptr, 10);
+ if (*endptr != '\0') {
+ LOG_WRN("Invalid profile index: %s", log_strdup(next));
+ return -EINVAL;
+ }
+
+ if (len != sizeof(struct zmk_ble_profile)) {
+ LOG_ERR("Invalid profile size (got %d expected %d)", len, sizeof(struct zmk_ble_profile));
+ return -EINVAL;
+ }
+
+ if (idx >= PROFILE_COUNT) {
+ LOG_WRN("Profile address for index %d is larger than max of %d", idx, PROFILE_COUNT);
+ return -EINVAL;
+ }
+
+ int err = read_cb(cb_arg, &profiles[idx], sizeof(struct zmk_ble_profile));
+ if (err <= 0) {
+ LOG_ERR("Failed to handle profile address from settings (err %d)", err);
+ return err;
+ }
+
+ char addr_str[BT_ADDR_LE_STR_LEN];
+ bt_addr_le_to_str(&profiles[idx].peer, addr_str, sizeof(addr_str));
+
+ LOG_DBG("Loaded %s address for profile %d", log_strdup(addr_str), idx);
+ } else if (settings_name_steq(name, "active_profile", &next) && !next) {
+ if (len != sizeof(active_profile)) {
+ return -EINVAL;
+ }
+
+ int err = read_cb(cb_arg, &active_profile, sizeof(active_profile));
+ if (err <= 0) {
+ LOG_ERR("Failed to handle active profile from settings (err %d)", err);
+ return err;
+ }
+ }
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+ else if (settings_name_steq(name, "peripheral_address", &next) && !next) {
+ if (len != sizeof(bt_addr_le_t)) {
+ return -EINVAL;
+ }
+
+ int err = read_cb(cb_arg, &peripheral_addr, sizeof(bt_addr_le_t));
+ if (err <= 0) {
+ LOG_ERR("Failed to handle peripheral address from settings (err %d)", err);
+ return err;
+ }
+ }
+#endif
+
+ return 0;
+};
+
+struct settings_handler profiles_handler = {
+ .name = "ble",
+ .h_set = ble_profiles_handle_set
+};
+#endif /* IS_ENABLED(CONFIG_SETTINGS) */
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));
if (err)
@@ -71,6 +285,14 @@ static void disconnected(struct bt_conn *conn, u8_t reason)
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
+
+#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
+ // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) {
+ // zmk_ble_adv_resume();
+ // }
+#else
+ // zmk_ble_adv_resume();
+#endif
}
static void security_changed(struct bt_conn *conn, bt_security_t level,
@@ -137,7 +359,52 @@ static void auth_cancel(struct bt_conn *conn)
LOG_DBG("Pairing cancelled: %s", log_strdup(addr));
}
+#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const struct bt_conn_pairing_feat *const feat)
+{
+ struct bt_conn_info info;
+ bt_conn_get_info(conn, &info);
+
+ LOG_DBG("role %d, open? %s", info.role, active_profile_is_open() ? "yes" : "no");
+ if (info.role == BT_CONN_ROLE_SLAVE && !active_profile_is_open()) {
+ LOG_WRN("Rejecting pairing request to taken profile %d", active_profile);
+ return BT_SECURITY_ERR_PAIR_NOT_ALLOWED;
+ }
+
+ return BT_SECURITY_ERR_SUCCESS;
+};
+#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
+
+static void auth_pairing_complete(struct bt_conn *conn, bool bonded)
+{
+ struct bt_conn_info info;
+ char addr[BT_ADDR_LE_STR_LEN];
+ const bt_addr_le_t *dst = bt_conn_get_dst(conn);
+
+ bt_addr_le_to_str(dst, addr, sizeof(addr));
+ bt_conn_get_info(conn, &info);
+
+ if (info.role != BT_CONN_ROLE_SLAVE) {
+ LOG_DBG("SKIPPING FOR ROLE %d", info.role);
+ return;
+ }
+
+#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ if (!active_profile_is_open()) {
+ LOG_ERR("Pairing completed but current profile is not open: %s", log_strdup(addr));
+ bt_unpair(BT_ID_DEFAULT, dst);
+ return;
+ }
+#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
+
+ set_profile_address(active_profile, dst);
+};
+
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
+#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
+ .pairing_accept = auth_pairing_accept,
+#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */
+ .pairing_complete = auth_pairing_complete,
// .passkey_display = auth_passkey_display,
#ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY
@@ -146,19 +413,6 @@ static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
.cancel = auth_cancel,
};
-static const struct bt_data zmk_ble_ad[] = {
- BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
- BT_DATA_BYTES(BT_DATA_UUID16_SOME,
-#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
- 0x12, 0x18, /* HID Service */
-#endif
- 0x0f, 0x18 /* Battery Service */
- ),
-#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
- BT_DATA_BYTES(BT_DATA_UUID128_ALL,
- ZMK_SPLIT_BT_SERVICE_UUID)
-#endif
-};
static void zmk_ble_ready(int err)
{
@@ -169,12 +423,7 @@ static void zmk_ble_ready(int err)
return;
}
- err = bt_le_adv_start(ZMK_ADV_PARAMS, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
- if (err)
- {
- LOG_ERR("Advertising failed to start (err %d)", err);
- return;
- }
+ zmk_ble_adv_resume();
}
static int zmk_ble_init(struct device *_arg)
@@ -187,11 +436,37 @@ static int zmk_ble_init(struct device *_arg)
return err;
}
- if (IS_ENABLED(CONFIG_BT_SETTINGS))
- {
- settings_load();
+#if IS_ENABLED(CONFIG_SETTINGS)
+ settings_subsys_init();
+
+ err = settings_register(&profiles_handler);
+ if (err) {
+ LOG_ERR("Failed to setup the profile settings handler (err %d)", err);
+ return err;
+ }
+
+ settings_load();
+
+#endif
+
+#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START)
+ LOG_WRN("Clearing all existing BLE bond information from the keyboard");
+
+ for (int i = 0; i < 10; i++) {
+ bt_unpair(i, NULL);
}
+ for (int i = 0; i < PROFILE_COUNT; i++) {
+ char setting_name[15];
+ sprintf(setting_name, "ble/profiles/%d", i);
+
+ err = settings_delete(setting_name);
+ if (err) {
+ LOG_ERR("Failed to delete setting: %d", err);
+ }
+ }
+#endif
+
bt_conn_cb_register(&conn_callbacks);
bt_conn_auth_cb_register(&zmk_ble_auth_cb_display);
@@ -202,8 +477,17 @@ static int zmk_ble_init(struct device *_arg)
int zmk_ble_unpair_all()
{
- LOG_DBG("");
- return bt_unpair(BT_ID_DEFAULT, NULL);
+ int resp = 0;
+ for (int i = BT_ID_DEFAULT; i < CONFIG_BT_ID_MAX; i++) {
+
+ int err = bt_unpair(BT_ID_DEFAULT, NULL);
+ if (err) {
+ resp = err;
+ LOG_ERR("Failed to unpair devices (err %d)", err);
+ }
+ }
+
+ return resp;
};
bool zmk_ble_handle_key_user(struct zmk_key_event *key_event)
diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c
new file mode 100644
index 0000000..a270a14
--- /dev/null
+++ b/app/src/events/ble_active_profile_changed.c
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <kernel.h>
+#include <zmk/events/ble-active-profile-changed.h>
+
+ZMK_EVENT_IMPL(ble_active_profile_changed); \ No newline at end of file
diff --git a/app/src/hog.c b/app/src/hog.c
index 92858d5..93e6d9b 100644
--- a/app/src/hog.c
+++ b/app/src/hog.c
@@ -6,6 +6,10 @@
#include <settings/settings.h>
+#include <logging/log.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>
@@ -148,12 +152,40 @@ BT_GATT_SERVICE_DEFINE(hog_svc,
BT_GATT_PERM_WRITE,
NULL, write_ctrl_point, &ctrl_point));
+struct bt_conn *destination_connection() {
+ struct bt_conn *conn;
+ bt_addr_le_t *addr = zmk_ble_active_profile_addr();
+ LOG_DBG("Address pointer %p", addr);
+ if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
+ LOG_WRN("Not sending, no active address for current profile");
+ return NULL;
+ } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
+ LOG_WRN("Not sending, not connected to active profile");
+ return NULL;
+ }
+
+ return conn;
+
+}
+
int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report)
{
- return bt_gatt_notify(NULL, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body));
+ struct bt_conn *conn = destination_connection();
+ if (conn == NULL) {
+ return -ENOTCONN;
+ }
+
+ LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no");
+
+ return bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body));
};
int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report)
{
- return bt_gatt_notify(NULL, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body));
+ struct bt_conn *conn = destination_connection();
+ if (conn == NULL) {
+ return -ENOTCONN;
+ }
+
+ return bt_gatt_notify(conn, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body));
};
diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c
index 9e67228..6d8b435 100644
--- a/app/src/split/bluetooth/central.c
+++ b/app/src/split/bluetooth/central.c
@@ -10,12 +10,14 @@
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
#include <sys/byteorder.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+#include <zmk/ble.h>
#include <zmk/split/bluetooth/uuid.h>
#include <zmk/event-manager.h>
#include <zmk/events/position-state-changed.h>
@@ -71,6 +73,27 @@ static u8_t split_central_notify_func(struct bt_conn *conn,
return BT_GATT_ITER_CONTINUE;
}
+static int split_central_subscribe(struct bt_conn *conn)
+{
+ int err = bt_gatt_subscribe(conn, &subscribe_params);
+ switch (err) {
+ case -EALREADY:
+ LOG_DBG("[ALREADY SUBSCRIBED]");
+ break;
+ // break;
+ // bt_gatt_unsubscribe(conn, &subscribe_params);
+ // return split_central_subscribe(conn);
+ case 0:
+ LOG_DBG("[SUBSCRIBED]");
+ break;
+ default:
+ LOG_ERR("Subscribe failed (err %d)", err);
+ break;
+ }
+
+ return 0;
+}
+
static u8_t split_central_discovery_func(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
@@ -112,12 +135,7 @@ static u8_t split_central_discovery_func(struct bt_conn *conn,
subscribe_params.value = BT_GATT_CCC_NOTIFY;
subscribe_params.ccc_handle = attr->handle;
- err = bt_gatt_subscribe(conn, &subscribe_params);
- if (err && err != -EALREADY) {
- LOG_ERR("Subscribe failed (err %d)", err);
- } else {
- LOG_DBG("[SUBSCRIBED]");
- }
+ split_central_subscribe(conn);
return BT_GATT_ITER_STOP;
}
@@ -136,7 +154,7 @@ static void split_central_process_connection(struct bt_conn *conn) {
return;
}
- if (conn == default_conn) {
+ if (conn == default_conn && !subscribe_params.value) {
discover_params.uuid = &uuid.uuid;
discover_params.func = split_central_discovery_func;
discover_params.start_handle = 0x0001;
@@ -194,6 +212,8 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data)
LOG_DBG("Found the split service");
+ zmk_ble_set_peripheral_addr(addr);
+
err = bt_le_scan_stop();
if (err) {
LOG_ERR("Stop LE scan failed (err %d)", err);
@@ -206,10 +226,11 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data)
split_central_process_connection(default_conn);
} else {
param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400);
+
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
param, &default_conn);
if (err) {
- LOG_ERR("Create conn failed (err %d)", err);
+ LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN);
start_scan();
}
@@ -263,8 +284,9 @@ static void split_central_connected(struct bt_conn *conn, u8_t conn_err)
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
if (conn_err) {
- LOG_ERR("Failed to connect to %s (%u)", addr, conn_err);
+ LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err);
bt_conn_unref(default_conn);
default_conn = NULL;
diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c
index 0a5ddb7..c2f65d2 100644
--- a/app/src/split/bluetooth/service.c
+++ b/app/src/split/bluetooth/service.c
@@ -6,6 +6,11 @@
#include <zephyr/types.h>
#include <sys/util.h>
+
+#include <logging/log.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
#include <bluetooth/gatt.h>
#include <bluetooth/uuid.h>
@@ -28,6 +33,7 @@ static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_
static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, u16_t value)
{
+ LOG_DBG("value %d", value);
}
diff --git a/app/src/split_listener.c b/app/src/split_listener.c
index 46a95e1..1263807 100644
--- a/app/src/split_listener.c
+++ b/app/src/split_listener.c
@@ -21,12 +21,13 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
int split_listener(const struct zmk_event_header *eh)
{
+ LOG_DBG("");
if (is_position_state_changed(eh)) {
const struct position_state_changed *ev = cast_position_state_changed(eh);
if (ev->state) {
- zmk_split_bt_position_pressed(ev->position);
+ return zmk_split_bt_position_pressed(ev->position);
} else {
- zmk_split_bt_position_released(ev->position);
+ return zmk_split_bt_position_released(ev->position);
}
}
return 0;