summaryrefslogtreecommitdiff
path: root/app/src/split/bluetooth
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/split/bluetooth')
-rw-r--r--app/src/split/bluetooth/central.c49
-rw-r--r--app/src/split/bluetooth/service.c50
2 files changed, 97 insertions, 2 deletions
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), );