From 4e4faca67015df3a3e1bf1b9937265f465c5093d Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 20 Dec 2020 09:49:42 -0500 Subject: feature(split): behavior locality support. * GATT characteristic allowing passng data + behavior label to invoke the behavior on the peripheral side. * Behaviors have a locality setting to specify where they run. * Build reset/power/RGB on peripheral. --- app/src/split/bluetooth/service.c | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'app/src/split/bluetooth/service.c') diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index fbac644..bb0202c 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -15,6 +15,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#include +#include #include #include #include @@ -24,12 +26,57 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static uint8_t num_of_positions = ZMK_KEYMAP_LEN; static uint8_t position_state[POS_STATE_LEN]; +static struct zmk_split_run_behavior_payload behavior_run_payload; + static ssize_t split_svc_pos_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attrs, buf, len, offset, &position_state, sizeof(position_state)); } +static ssize_t split_svc_run_behavior(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + const void *buf, uint16_t len, uint16_t offset, + uint8_t flags) { + struct zmk_split_run_behavior_payload *payload = attrs->user_data; + uint16_t end_addr = offset + len; + + LOG_DBG("offset %d len %d", offset, len); + + if (end_addr > sizeof(struct zmk_split_run_behavior_payload)) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + + memcpy(payload + offset, buf, len); + + // We run if: + // 1: We've gotten all the position/state/param data. + // 2: We have a null terminated string for the behavior device label. + if ((end_addr > sizeof(struct zmk_split_run_behavior_data)) && + payload->behavior_dev[end_addr - sizeof(struct zmk_split_run_behavior_data)] == '\0') { + struct zmk_behavior_binding binding = { + .param1 = payload->data.param1, + .param2 = payload->data.param2, + .behavior_dev = payload->behavior_dev, + }; + LOG_DBG("INVOKE THE BEHAVIOR: %s with params %d %d", log_strdup(binding.behavior_dev), + binding.param1, binding.param2); + struct zmk_behavior_binding_event event = {.position = payload->data.position, + .timestamp = k_uptime_get()}; + int err; + if (payload->data.state > 0) { + err = behavior_keymap_binding_pressed(&binding, event); + } else { + err = behavior_keymap_binding_released(&binding, event); + } + + if (err) { + LOG_ERR("Failed to invoke behavior %s: %d", log_strdup(binding.behavior_dev), err); + } + } + + return len; +} + static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, uint16_t len, uint16_t offset) { return bt_gatt_attr_read(conn, attrs, buf, len, offset, attrs->user_data, sizeof(uint8_t)); @@ -45,6 +92,9 @@ BT_GATT_SERVICE_DEFINE( BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, split_svc_pos_state, NULL, &position_state), BT_GATT_CCC(split_svc_pos_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), + BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL, + split_svc_run_behavior, &behavior_run_payload), BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL, &num_of_positions), ); -- cgit v1.2.3