Browse Source

refactor(splits): Use index for event source.

* Track peripherals by indexes slot, with all appropiate peripheral
  state stored in the slot.
* Event sources tracked by peripheral slot index.
xmkb
Peter Johanson 3 years ago committed by Pete Johanson
parent
commit
9297c5f2b4
  1. 11
      app/include/zmk/ble.h
  2. 9
      app/include/zmk/events/position_state_changed.h
  3. 4
      app/include/zmk/keymap.h
  4. 2
      app/include/zmk/split/bluetooth/central.h
  5. 16
      app/src/ble.c
  6. 25
      app/src/keymap.c
  7. 11
      app/src/kscan.c
  8. 279
      app/src/split/bluetooth/central.c

11
app/include/zmk/ble.h

@ -9,6 +9,17 @@
#include <zmk/keys.h> #include <zmk/keys.h>
#include <zmk/ble/profile.h> #include <zmk/ble/profile.h>
#define ZMK_BLE_IS_CENTRAL \
(IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \
IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
#if ZMK_BLE_IS_CENTRAL
#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
#define ZMK_BLE_SPLIT_PERIPHERAL_COUNT 1
#else
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
#endif
int zmk_ble_clear_bonds(); int zmk_ble_clear_bonds();
int zmk_ble_prof_next(); int zmk_ble_prof_next();
int zmk_ble_prof_prev(); int zmk_ble_prof_prev();

9
app/include/zmk/events/position_state_changed.h

@ -8,16 +8,9 @@
#include <zephyr.h> #include <zephyr.h>
#include <zmk/event_manager.h> #include <zmk/event_manager.h>
#include <bluetooth/addr.h>
#if IS_ENABLED(CONFIG_ZMK_BLE)
typedef const bt_addr_le_t *zmk_position_state_changed_source_t;
#else
typedef void *zmk_position_state_changed_source_t;
#endif
struct zmk_position_state_changed { struct zmk_position_state_changed {
zmk_position_state_changed_source_t source; uint8_t source;
uint32_t position; uint32_t position;
bool state; bool state;
int64_t timestamp; int64_t timestamp;

4
app/include/zmk/keymap.h

@ -20,8 +20,8 @@ int zmk_keymap_layer_toggle(uint8_t layer);
int zmk_keymap_layer_to(uint8_t layer); int zmk_keymap_layer_to(uint8_t layer);
const char *zmk_keymap_layer_label(uint8_t layer); const char *zmk_keymap_layer_label(uint8_t layer);
int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
bool pressed, int64_t timestamp); int64_t timestamp);
#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \ #define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \
{ \ { \

2
app/include/zmk/split/bluetooth/central.h

@ -4,5 +4,5 @@
#include <bluetooth/addr.h> #include <bluetooth/addr.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event, bool state); struct zmk_behavior_binding_event event, bool state);

16
app/src/ble.c

@ -72,7 +72,7 @@ enum advertising_type {
BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \ BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \
BT_GAP_ADV_FAST_INT_MAX_2, NULL) BT_GAP_ADV_FAST_INT_MAX_2, NULL)
static struct zmk_ble_profile profiles[PROFILE_COUNT]; static struct zmk_ble_profile profiles[ZMK_BLE_PROFILE_COUNT];
static uint8_t active_profile; static uint8_t active_profile;
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
@ -260,7 +260,7 @@ static int ble_save_profile() {
} }
int zmk_ble_prof_select(uint8_t index) { int zmk_ble_prof_select(uint8_t index) {
if (index >= PROFILE_COUNT) { if (index >= ZMK_BLE_PROFILE_COUNT) {
return -ERANGE; return -ERANGE;
} }
@ -281,12 +281,13 @@ int zmk_ble_prof_select(uint8_t index) {
int zmk_ble_prof_next() { int zmk_ble_prof_next() {
LOG_DBG(""); LOG_DBG("");
return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT); return zmk_ble_prof_select((active_profile + 1) % ZMK_BLE_PROFILE_COUNT);
}; };
int zmk_ble_prof_prev() { int zmk_ble_prof_prev() {
LOG_DBG(""); LOG_DBG("");
return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT); return zmk_ble_prof_select((active_profile + ZMK_BLE_PROFILE_COUNT - 1) %
ZMK_BLE_PROFILE_COUNT);
}; };
bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; } bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; }
@ -324,8 +325,9 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
return -EINVAL; return -EINVAL;
} }
if (idx >= PROFILE_COUNT) { if (idx >= ZMK_BLE_PROFILE_COUNT) {
LOG_WRN("Profile address for index %d is larger than max of %d", idx, PROFILE_COUNT); LOG_WRN("Profile address for index %d is larger than max of %d", idx,
ZMK_BLE_PROFILE_COUNT);
return -EINVAL; return -EINVAL;
} }
@ -591,7 +593,7 @@ static int zmk_ble_init(const struct device *_arg) {
bt_unpair(i, NULL); bt_unpair(i, NULL);
} }
for (int i = 0; i < PROFILE_COUNT; i++) { for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) {
char setting_name[15]; char setting_name[15];
sprintf(setting_name, "ble/profiles/%d", i); sprintf(setting_name, "ble/profiles/%d", i);

25
app/src/keymap.c

@ -4,10 +4,6 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#define IS_BLE_CENTRAL \
(IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \
IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
#include <sys/util.h> #include <sys/util.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
#include <logging/log.h> #include <logging/log.h>
@ -19,7 +15,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <drivers/behavior.h> #include <drivers/behavior.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#if IS_BLE_CENTRAL #include <zmk/ble.h>
#if ZMK_BLE_IS_CENTRAL
#include <zmk/split/bluetooth/central.h> #include <zmk/split/bluetooth/central.h>
#endif #endif
@ -170,8 +167,8 @@ int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_bin
} }
} }
int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, int layer, int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position, bool pressed,
uint32_t position, bool pressed, int64_t timestamp) { int64_t timestamp) {
// We want to make a copy of this, since it may be converted from // We want to make a copy of this, since it may be converted from
// relative to absolute before being invoked // relative to absolute before being invoked
struct zmk_behavior_binding binding = zmk_keymap[layer][position]; struct zmk_behavior_binding binding = zmk_keymap[layer][position];
@ -209,8 +206,8 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source,
case BEHAVIOR_LOCALITY_CENTRAL: case BEHAVIOR_LOCALITY_CENTRAL:
return invoke_locally(&binding, event, pressed); return invoke_locally(&binding, event, pressed);
case BEHAVIOR_LOCALITY_EVENT_SOURCE: case BEHAVIOR_LOCALITY_EVENT_SOURCE:
#if IS_BLE_CENTRAL #if ZMK_BLE_IS_CENTRAL
if (!bt_addr_le_cmp(source, BT_ADDR_LE_NONE)) { if (source == UINT_MAX) {
return invoke_locally(&binding, event, pressed); return invoke_locally(&binding, event, pressed);
} else { } else {
return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); return zmk_split_bt_invoke_behavior(source, &binding, event, pressed);
@ -219,8 +216,10 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source,
return invoke_locally(&binding, event, pressed); return invoke_locally(&binding, event, pressed);
#endif #endif
case BEHAVIOR_LOCALITY_GLOBAL: case BEHAVIOR_LOCALITY_GLOBAL:
#if IS_BLE_CENTRAL #if ZMK_BLE_IS_CENTRAL
zmk_split_bt_invoke_behavior(BT_ADDR_LE_ANY, &binding, event, pressed); for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
zmk_split_bt_invoke_behavior(i, &binding, event, pressed);
}
#endif #endif
return invoke_locally(&binding, event, pressed); return invoke_locally(&binding, event, pressed);
} }
@ -228,8 +227,8 @@ int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source,
return -ENOTSUP; return -ENOTSUP;
} }
int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
bool pressed, int64_t timestamp) { int64_t timestamp) {
if (pressed) { if (pressed) {
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
} }

11
app/src/kscan.c

@ -50,12 +50,11 @@ void zmk_kscan_process_msgq(struct k_work *item) {
uint32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); uint32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column);
LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position, LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position,
(pressed ? "true" : "false")); (pressed ? "true" : "false"));
ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed) { ZMK_EVENT_RAISE(new_zmk_position_state_changed(
#if IS_ENABLED(CONFIG_ZMK_BLE) (struct zmk_position_state_changed){.source = UINT8_MAX,
.source = BT_ADDR_LE_NONE, .state = pressed,
#endif .position = position,
.state = pressed, .position = position, .timestamp = k_uptime_get() .timestamp = k_uptime_get()}));
}));
} }
} }

279
app/src/split/bluetooth/central.c

@ -29,17 +29,112 @@ static int start_scan(void);
#define POSITION_STATE_DATA_LEN 16 #define POSITION_STATE_DATA_LEN 16
static struct bt_conn *default_conn; enum peripheral_slot_state {
PERIPHERAL_SLOT_STATE_OPEN,
PERIPHERAL_SLOT_STATE_CONNECTING,
PERIPHERAL_SLOT_STATE_CONNECTED,
};
struct peripheral_slot {
enum peripheral_slot_state state;
struct bt_conn *conn;
struct bt_gatt_discover_params discover_params;
struct bt_gatt_subscribe_params subscribe_params;
struct bt_gatt_discover_params sub_discover_params;
uint16_t run_behavior_handle;
uint8_t position_state[POSITION_STATE_DATA_LEN];
uint8_t changed_positions[POSITION_STATE_DATA_LEN];
};
static struct peripheral_slot peripherals[ZMK_BLE_SPLIT_PERIPHERAL_COUNT];
static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID); static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID);
static struct bt_gatt_discover_params discover_params;
static struct bt_gatt_subscribe_params subscribe_params;
static struct bt_gatt_discover_params sub_discover_params;
static uint16_t run_behavior_handle;
K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed), K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed),
CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4);
int peripheral_slot_index_for_conn(struct bt_conn *conn) {
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
if (peripherals[i].conn == conn) {
return i;
}
}
return -EINVAL;
}
struct peripheral_slot *peripheral_slot_for_conn(struct bt_conn *conn) {
int idx = peripheral_slot_index_for_conn(conn);
if (idx < 0) {
return NULL;
}
return &peripherals[idx];
}
int release_peripheral_slot(int index) {
if (index < 0 || index >= ZMK_BLE_SPLIT_PERIPHERAL_COUNT) {
return -EINVAL;
}
struct peripheral_slot *slot = &peripherals[index];
if (slot->state == PERIPHERAL_SLOT_STATE_OPEN) {
return -EINVAL;
}
LOG_DBG("Releasing peripheral slot at %d", index);
if (slot->conn != NULL) {
bt_conn_unref(slot->conn);
slot->conn = NULL;
}
slot->state = PERIPHERAL_SLOT_STATE_OPEN;
for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) {
slot->position_state[i] = 0U;
slot->changed_positions[i] = 0U;
}
// Clean up previously discovered handles;
slot->subscribe_params.value_handle = 0;
slot->run_behavior_handle = 0;
return 0;
}
int reserve_peripheral_slot() {
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
if (peripherals[i].state == PERIPHERAL_SLOT_STATE_OPEN) {
// Be sure the slot is fully reinitialized.
release_peripheral_slot(i);
peripherals[i].state = PERIPHERAL_SLOT_STATE_CONNECTING;
return i;
}
}
return -ENOMEM;
}
int release_peripheral_slot_for_conn(struct bt_conn *conn) {
int idx = peripheral_slot_index_for_conn(conn);
if (idx < 0) {
return idx;
}
return release_peripheral_slot(idx);
}
int confirm_peripheral_slot_conn(struct bt_conn *conn) {
int idx = peripheral_slot_index_for_conn(conn);
if (idx < 0) {
return idx;
}
peripherals[idx].state = PERIPHERAL_SLOT_STATE_CONNECTED;
return 0;
}
void peripheral_event_work_callback(struct k_work *work) { void peripheral_event_work_callback(struct k_work *work) {
struct zmk_position_state_changed ev; struct zmk_position_state_changed ev;
while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) { while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) {
@ -53,9 +148,12 @@ K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback);
static uint8_t split_central_notify_func(struct bt_conn *conn, static uint8_t split_central_notify_func(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params, const void *data, struct bt_gatt_subscribe_params *params, const void *data,
uint16_t length) { uint16_t length) {
static uint8_t position_state[POSITION_STATE_DATA_LEN]; struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
uint8_t changed_positions[POSITION_STATE_DATA_LEN]; if (slot == NULL) {
LOG_ERR("No peripheral state found for connection");
return BT_GATT_ITER_CONTINUE;
}
if (!data) { if (!data) {
LOG_DBG("[UNSUBSCRIBED]"); LOG_DBG("[UNSUBSCRIBED]");
@ -66,16 +164,18 @@ static uint8_t split_central_notify_func(struct bt_conn *conn,
LOG_DBG("[NOTIFICATION] data %p length %u", data, length); LOG_DBG("[NOTIFICATION] data %p length %u", data, length);
for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) {
changed_positions[i] = ((uint8_t *)data)[i] ^ position_state[i]; slot->changed_positions[i] = ((uint8_t *)data)[i] ^ slot->position_state[i];
position_state[i] = ((uint8_t *)data)[i]; slot->position_state[i] = ((uint8_t *)data)[i];
LOG_DBG("data: %d", slot->position_state[i]);
} }
for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) {
for (int j = 0; j < 8; j++) { for (int j = 0; j < 8; j++) {
if (changed_positions[i] & BIT(j)) { if (slot->changed_positions[i] & BIT(j)) {
uint32_t position = (i * 8) + j; uint32_t position = (i * 8) + j;
bool pressed = position_state[i] & BIT(j); bool pressed = slot->position_state[i] & BIT(j);
struct zmk_position_state_changed ev = {.source = bt_conn_get_dst(conn), struct zmk_position_state_changed ev = {.source =
peripheral_slot_index_for_conn(conn),
.position = position, .position = position,
.state = pressed, .state = pressed,
.timestamp = k_uptime_get()}; .timestamp = k_uptime_get()};
@ -90,7 +190,13 @@ static uint8_t split_central_notify_func(struct bt_conn *conn,
} }
static void split_central_subscribe(struct bt_conn *conn) { static void split_central_subscribe(struct bt_conn *conn) {
int err = bt_gatt_subscribe(conn, &subscribe_params); struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
if (slot == NULL) {
LOG_ERR("No peripheral state found for connection");
return;
}
int err = bt_gatt_subscribe(conn, &slot->subscribe_params);
switch (err) { switch (err) {
case -EALREADY: case -EALREADY:
LOG_DBG("[ALREADY SUBSCRIBED]"); LOG_DBG("[ALREADY SUBSCRIBED]");
@ -117,28 +223,34 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
return BT_GATT_ITER_STOP; return BT_GATT_ITER_STOP;
} }
struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
if (slot == NULL) {
LOG_ERR("No peripheral state found for connection");
return BT_GATT_ITER_STOP;
}
LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); LOG_DBG("[ATTRIBUTE] handle %u", attr->handle);
if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) { BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) {
LOG_DBG("Found position state characteristic"); LOG_DBG("Found position state characteristic");
discover_params.uuid = NULL; slot->discover_params.uuid = NULL;
discover_params.start_handle = attr->handle + 2; slot->discover_params.start_handle = attr->handle + 2;
discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
subscribe_params.disc_params = &sub_discover_params; slot->subscribe_params.disc_params = &slot->sub_discover_params;
subscribe_params.end_handle = discover_params.end_handle; slot->subscribe_params.end_handle = slot->discover_params.end_handle;
subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
subscribe_params.notify = split_central_notify_func; slot->subscribe_params.notify = split_central_notify_func;
subscribe_params.value = BT_GATT_CCC_NOTIFY; slot->subscribe_params.value = BT_GATT_CCC_NOTIFY;
split_central_subscribe(conn); split_central_subscribe(conn);
} else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid, } else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) {
LOG_DBG("Found run behavior handle"); LOG_DBG("Found run behavior handle");
run_behavior_handle = bt_gatt_attr_value_handle(attr); slot->run_behavior_handle = bt_gatt_attr_value_handle(attr);
} }
bool subscribed = (run_behavior_handle && subscribe_params.value_handle); bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle);
return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE;
} }
@ -154,18 +266,24 @@ static uint8_t split_central_service_discovery_func(struct bt_conn *conn,
LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); LOG_DBG("[ATTRIBUTE] handle %u", attr->handle);
if (bt_uuid_cmp(discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
if (slot == NULL) {
LOG_ERR("No peripheral state found for connection");
return BT_GATT_ITER_STOP;
}
if (bt_uuid_cmp(slot->discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) {
LOG_DBG("Found other service"); LOG_DBG("Found other service");
return BT_GATT_ITER_CONTINUE; return BT_GATT_ITER_CONTINUE;
} }
LOG_DBG("Found split service"); LOG_DBG("Found split service");
discover_params.uuid = NULL; slot->discover_params.uuid = NULL;
discover_params.func = split_central_chrc_discovery_func; slot->discover_params.func = split_central_chrc_discovery_func;
discover_params.start_handle = attr->handle + 1; slot->discover_params.start_handle = attr->handle + 1;
discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
int err = bt_gatt_discover(conn, &discover_params); int err = bt_gatt_discover(conn, &slot->discover_params);
if (err) { if (err) {
LOG_ERR("Failed to start discovering split service characteristics (err %d)", err); LOG_ERR("Failed to start discovering split service characteristics (err %d)", err);
} }
@ -183,14 +301,20 @@ static void split_central_process_connection(struct bt_conn *conn) {
return; return;
} }
if (conn == default_conn && !subscribe_params.value_handle) { struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
discover_params.uuid = &split_service_uuid.uuid; if (slot == NULL) {
discover_params.func = split_central_service_discovery_func; LOG_ERR("No peripheral state found for connection");
discover_params.start_handle = 0x0001; return;
discover_params.end_handle = 0xffff; }
discover_params.type = BT_GATT_DISCOVER_PRIMARY;
err = bt_gatt_discover(default_conn, &discover_params); if (!slot->subscribe_params.value_handle) {
slot->discover_params.uuid = &split_service_uuid.uuid;
slot->discover_params.func = split_central_service_discovery_func;
slot->discover_params.start_handle = 0x0001;
slot->discover_params.end_handle = 0xffff;
slot->discover_params.type = BT_GATT_DISCOVER_PRIMARY;
err = bt_gatt_discover(slot->conn, &slot->discover_params);
if (err) { if (err) {
LOG_ERR("Discover failed(err %d)", err); LOG_ERR("Discover failed(err %d)", err);
return; return;
@ -251,21 +375,33 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) {
continue; continue;
} }
default_conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); uint8_t slot_idx = reserve_peripheral_slot();
if (default_conn) { if (slot_idx < 0) {
LOG_ERR("Faild to reserve peripheral slot (err %d)", slot_idx);
continue;
}
struct peripheral_slot *slot = &peripherals[slot_idx];
slot->conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
if (slot->conn) {
LOG_DBG("Found existing connection"); LOG_DBG("Found existing connection");
split_central_process_connection(default_conn); split_central_process_connection(slot->conn);
err = bt_conn_le_phy_update(slot->conn, BT_CONN_LE_PHY_PARAM_2M);
if (err) {
LOG_ERR("Update phy conn failed (err %d)", err);
}
} else { } else {
param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400); param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400);
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &slot->conn);
if (err) { if (err) {
LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err,
BT_HCI_OP_LE_CREATE_CONN); BT_HCI_OP_LE_CREATE_CONN);
start_scan(); start_scan();
} }
err = bt_conn_le_phy_update(default_conn, BT_CONN_LE_PHY_PARAM_2M); err = bt_conn_le_phy_update(slot->conn, BT_CONN_LE_PHY_PARAM_2M);
if (err) { if (err) {
LOG_ERR("Update phy conn failed (err %d)", err); LOG_ERR("Update phy conn failed (err %d)", err);
start_scan(); start_scan();
@ -314,8 +450,7 @@ static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) {
if (conn_err) { if (conn_err) {
LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err); LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err);
bt_conn_unref(default_conn); release_peripheral_slot_for_conn(conn);
default_conn = NULL;
start_scan(); start_scan();
return; return;
@ -323,6 +458,7 @@ static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) {
LOG_DBG("Connected: %s", log_strdup(addr)); LOG_DBG("Connected: %s", log_strdup(addr));
confirm_peripheral_slot_conn(conn);
split_central_process_connection(conn); split_central_process_connection(conn);
} }
@ -333,16 +469,7 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) {
LOG_DBG("Disconnected: %s (reason %d)", log_strdup(addr), reason); LOG_DBG("Disconnected: %s (reason %d)", log_strdup(addr), reason);
if (default_conn != conn) { release_peripheral_slot_for_conn(conn);
return;
}
bt_conn_unref(default_conn);
default_conn = NULL;
// Clean up previously discovered handles;
subscribe_params.value_handle = 0;
run_behavior_handle = 0;
start_scan(); start_scan();
} }
@ -357,16 +484,30 @@ K_THREAD_STACK_DEFINE(split_central_split_run_q_stack,
struct k_work_q split_central_split_run_q; struct k_work_q split_central_split_run_q;
K_MSGQ_DEFINE(zmk_split_central_split_run_msgq, sizeof(struct zmk_split_run_behavior_payload), struct zmk_split_run_behavior_payload_wrapper {
uint8_t source;
struct zmk_split_run_behavior_payload payload;
};
K_MSGQ_DEFINE(zmk_split_central_split_run_msgq,
sizeof(struct zmk_split_run_behavior_payload_wrapper),
CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4); CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4);
void split_central_split_run_callback(struct k_work *work) { void split_central_split_run_callback(struct k_work *work) {
struct zmk_split_run_behavior_payload payload; struct zmk_split_run_behavior_payload_wrapper payload_wrapper;
while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload, K_NO_WAIT) == 0) { LOG_DBG("");
int err =
bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, while (k_msgq_get(&zmk_split_central_split_run_msgq, &payload_wrapper, K_NO_WAIT) == 0) {
sizeof(struct zmk_split_run_behavior_payload), true); if (peripherals[payload_wrapper.source].state != PERIPHERAL_SLOT_STATE_CONNECTED) {
LOG_ERR("Source not connected");
continue;
}
int err = bt_gatt_write_without_response(
peripherals[payload_wrapper.source].conn,
peripherals[payload_wrapper.source].run_behavior_handle, &payload_wrapper.payload,
sizeof(struct zmk_split_run_behavior_payload), true);
if (err) { if (err) {
LOG_ERR("Failed to write the behavior characteristic (err %d)", err); LOG_ERR("Failed to write the behavior characteristic (err %d)", err);
@ -376,15 +517,18 @@ void split_central_split_run_callback(struct k_work *work) {
K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback); K_WORK_DEFINE(split_central_split_run_work, split_central_split_run_callback);
static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload payload) { static int
int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload, K_MSEC(100)); split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payload_wrapper payload_wrapper) {
LOG_DBG("");
int err = k_msgq_put(&zmk_split_central_split_run_msgq, &payload_wrapper, K_MSEC(100));
if (err) { if (err) {
switch (err) { switch (err) {
case -EAGAIN: { case -EAGAIN: {
LOG_WRN("Consumer message queue full, popping first message and queueing again"); LOG_WRN("Consumer message queue full, popping first message and queueing again");
struct zmk_split_run_behavior_payload discarded_report; struct zmk_split_run_behavior_payload_wrapper discarded_report;
k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT); k_msgq_get(&zmk_split_central_split_run_msgq, &discarded_report, K_NO_WAIT);
return split_bt_invoke_behavior_payload(payload); return split_bt_invoke_behavior_payload(payload_wrapper);
} }
default: default:
LOG_WRN("Failed to queue behavior to send (%d)", err); LOG_WRN("Failed to queue behavior to send (%d)", err);
@ -397,18 +541,19 @@ static int split_bt_invoke_behavior_payload(struct zmk_split_run_behavior_payloa
return 0; return 0;
}; };
int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, int zmk_split_bt_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event, bool state) { struct zmk_behavior_binding_event event, bool state) {
struct zmk_split_run_behavior_payload payload = {.data = { struct zmk_split_run_behavior_payload payload = {.data = {
.param1 = binding->param1, .param1 = binding->param1,
.param2 = binding->param2, .param2 = binding->param2,
.position = event.position, .position = event.position,
.state = state, .state = state ? 1 : 0,
}}; }};
strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1); strncpy(payload.behavior_dev, binding->behavior_dev, ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1);
payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0'; payload.behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN - 1] = '\0';
return split_bt_invoke_behavior_payload(payload); struct zmk_split_run_behavior_payload_wrapper wrapper = {.source = source, .payload = payload};
return split_bt_invoke_behavior_payload(wrapper);
} }
int zmk_split_bt_central_init(const struct device *_arg) { int zmk_split_bt_central_init(const struct device *_arg) {

Loading…
Cancel
Save