diff options
Diffstat (limited to 'app/src')
-rw-r--r-- | app/src/behaviors/behavior_ext_power.c | 1 | ||||
-rw-r--r-- | app/src/behaviors/behavior_reset.c | 1 | ||||
-rw-r--r-- | app/src/behaviors/behavior_rgb_underglow.c | 1 | ||||
-rw-r--r-- | app/src/keymap.c | 61 | ||||
-rw-r--r-- | app/src/kscan.c | 9 | ||||
-rw-r--r-- | app/src/split/bluetooth/central.c | 49 | ||||
-rw-r--r-- | app/src/split/bluetooth/service.c | 50 |
7 files changed, 159 insertions, 13 deletions
diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index fdd890c..2779331 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -71,6 +71,7 @@ static const struct behavior_driver_api behavior_ext_power_driver_api = { on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, }; DEVICE_DT_INST_DEFINE(0, behavior_ext_power_init, device_pm_control_nop, NULL, NULL, APPLICATION, diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index e19cf32..eb0477d 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -36,6 +36,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, static const struct behavior_driver_api behavior_reset_driver_api = { .binding_pressed = on_keymap_binding_pressed, + .locality = BEHAVIOR_LOCALITY_EVENT_SOURCE, }; #define RST_INST(n) \ diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 0243b54..33af655 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -134,6 +134,7 @@ static const struct behavior_driver_api behavior_rgb_underglow_driver_api = { on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, + .locality = BEHAVIOR_LOCALITY_GLOBAL, }; DEVICE_DT_INST_DEFINE(0, behavior_rgb_underglow_init, device_pm_control_nop, NULL, NULL, diff --git a/app/src/keymap.c b/app/src/keymap.c index 1643f64..16ec316 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -4,7 +4,12 @@ * 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 <bluetooth/bluetooth.h> #include <logging/log.h> LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -14,6 +19,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include <drivers/behavior.h> #include <zmk/behavior.h> +#if IS_BLE_CENTRAL +#include <zmk/split/bluetooth/central.h> +#endif + #include <zmk/event_manager.h> #include <zmk/events/position_state_changed.h> #include <zmk/events/layer_state_changed.h> @@ -152,7 +161,17 @@ const char *zmk_keymap_layer_label(uint8_t layer) { return zmk_keymap_layer_names[layer]; } -int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) { +int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, + bool pressed) { + if (pressed) { + return behavior_keymap_binding_pressed(binding, event); + } else { + return behavior_keymap_binding_released(binding, event); + } +} + +int zmk_keymap_apply_position_state(zmk_position_state_changed_source_t source, int layer, + uint32_t position, bool pressed, int64_t timestamp) { // We want to make a copy of this, since it may be converted from // relative to absolute before being invoked struct zmk_behavior_binding binding = zmk_keymap[layer][position]; @@ -169,7 +188,7 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, behavior = device_get_binding(binding.behavior_dev); if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", position, layer); + LOG_WRN("No behavior assigned to %d on layer %d", position, layer); return 1; } @@ -179,20 +198,44 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, return err; } - if (pressed) { - return behavior_keymap_binding_pressed(&binding, event); - } else { - return behavior_keymap_binding_released(&binding, event); + enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL; + err = behavior_get_locality(behavior, &locality); + if (err) { + LOG_ERR("Failed to get behavior locality %d", err); + return err; + } + + switch (locality) { + case BEHAVIOR_LOCALITY_CENTRAL: + return invoke_locally(&binding, event, pressed); + case BEHAVIOR_LOCALITY_EVENT_SOURCE: +#if IS_BLE_CENTRAL + if (!bt_addr_le_cmp(source, BT_ADDR_LE_NONE)) { + return invoke_locally(&binding, event, pressed); + } else { + return zmk_split_bt_invoke_behavior(source, &binding, event, pressed); + } +#else + return invoke_locally(&binding, event, pressed); +#endif + case BEHAVIOR_LOCALITY_GLOBAL: +#if IS_BLE_CENTRAL + zmk_split_bt_invoke_behavior(BT_ADDR_LE_ANY, &binding, event, pressed); +#endif + return invoke_locally(&binding, event, pressed); } + + return -ENOTSUP; } -int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp) { +int zmk_keymap_position_state_changed(zmk_position_state_changed_source_t source, uint32_t position, + bool pressed, int64_t timestamp) { if (pressed) { zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; } for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) { - int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp); + int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp); if (ret > 0) { LOG_DBG("behavior processing to continue to next layer"); continue; @@ -249,7 +292,7 @@ int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sens int keymap_listener(const zmk_event_t *eh) { const struct zmk_position_state_changed *pos_ev; if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { - return zmk_keymap_position_state_changed(pos_ev->position, pos_ev->state, + return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state, pos_ev->timestamp); } diff --git a/app/src/kscan.c b/app/src/kscan.c index 3c9c201..13ad2cc 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -6,6 +6,7 @@ #include <zephyr.h> #include <device.h> +#include <bluetooth/addr.h> #include <drivers/kscan.h> #include <logging/log.h> @@ -49,8 +50,12 @@ void zmk_kscan_process_msgq(struct k_work *item) { 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, (pressed ? "true" : "false")); - ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed){ - .state = pressed, .position = position, .timestamp = k_uptime_get()})); + ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed) { +#if IS_ENABLED(CONFIG_ZMK_BLE) + .source = BT_ADDR_LE_NONE, +#endif + .state = pressed, .position = position, .timestamp = k_uptime_get() + })); } } diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 9a7f01b..5ac4f83 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -18,7 +18,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include <zmk/ble.h> +#include <zmk/behavior.h> #include <zmk/split/bluetooth/uuid.h> +#include <zmk/split/bluetooth/service.h> #include <zmk/event_manager.h> #include <zmk/events/position_state_changed.h> #include <init.h> @@ -33,6 +35,7 @@ static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_ 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), CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4); @@ -72,8 +75,10 @@ static uint8_t split_central_notify_func(struct bt_conn *conn, if (changed_positions[i] & BIT(j)) { uint32_t position = (i * 8) + j; bool pressed = position_state[i] & BIT(j); - struct zmk_position_state_changed ev = { - .position = position, .state = pressed, .timestamp = k_uptime_get()}; + struct zmk_position_state_changed ev = {.source = bt_conn_get_dst(conn), + .position = position, + .state = pressed, + .timestamp = k_uptime_get()}; k_msgq_put(&peripheral_event_msgq, &ev, K_NO_WAIT); k_work_submit(&peripheral_event_work); @@ -124,9 +129,28 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn, subscribe_params.disc_params = &sub_discover_params; subscribe_params.end_handle = discover_params.end_handle; subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } + } else if (!bt_uuid_cmp(discover_params.uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID))) { + run_behavior_handle = bt_gatt_attr_value_handle(attr); + } else { subscribe_params.notify = split_central_notify_func; subscribe_params.value = BT_GATT_CCC_NOTIFY; split_central_subscribe(conn); + + memcpy(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID), sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } } return subscribe_params.value_handle ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE; @@ -340,6 +364,27 @@ static struct bt_conn_cb conn_callbacks = { .disconnected = split_central_disconnected, }; +int zmk_split_bt_invoke_behavior(const bt_addr_le_t *source, struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event, bool state) { + struct zmk_split_run_behavior_payload payload = {.data = { + .param1 = binding->param1, + .param2 = binding->param2, + .position = event.position, + .state = state, + }}; + 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'; + + int err = bt_gatt_write_without_response(default_conn, run_behavior_handle, &payload, + sizeof(struct zmk_split_run_behavior_payload), true); + + if (err) { + LOG_ERR("Failed to write the behavior characteristic (err %d)", err); + } + + return err; +}; + int zmk_split_bt_central_init(const struct device *_arg) { bt_conn_cb_register(&conn_callbacks); 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 <bluetooth/gatt.h> #include <bluetooth/uuid.h> +#include <drivers/behavior.h> +#include <zmk/behavior.h> #include <zmk/matrix.h> #include <zmk/split/bluetooth/uuid.h> #include <zmk/split/bluetooth/service.h> @@ -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), ); |