forked from kofal.net/zmk
feature(split): add support for sensors from peripheral
This commit adds a new GATT characteristics on the peripheral side and wires it up to read sensor values. The central side subscribes to this new characteristics and replays sensor values on its side. Co-authored-by: Peter Johanson <peter@peterjohanson.com>
This commit is contained in:
committed by
Pete Johanson
parent
c957348e61
commit
9d44229800
@@ -21,10 +21,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
#include <zmk/stdlib.h>
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/sensors.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 <zmk/events/sensor_event.h>
|
||||
|
||||
static int start_scanning(void);
|
||||
|
||||
@@ -41,6 +43,7 @@ struct peripheral_slot {
|
||||
struct bt_conn *conn;
|
||||
struct bt_gatt_discover_params discover_params;
|
||||
struct bt_gatt_subscribe_params subscribe_params;
|
||||
struct bt_gatt_subscribe_params sensor_subscribe_params;
|
||||
struct bt_gatt_discover_params sub_discover_params;
|
||||
uint16_t run_behavior_handle;
|
||||
uint8_t position_state[POSITION_STATE_DATA_LEN];
|
||||
@@ -165,6 +168,52 @@ int confirm_peripheral_slot_conn(struct bt_conn *conn) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
K_MSGQ_DEFINE(peripheral_sensor_event_msgq, sizeof(struct zmk_sensor_event),
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4);
|
||||
|
||||
void peripheral_sensor_event_work_callback(struct k_work *work) {
|
||||
struct zmk_sensor_event ev;
|
||||
while (k_msgq_get(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT) == 0) {
|
||||
LOG_DBG("Trigger sensor change for %d", ev.sensor_index);
|
||||
ZMK_EVENT_RAISE(new_zmk_sensor_event(ev));
|
||||
}
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(peripheral_sensor_event_work, peripheral_sensor_event_work_callback);
|
||||
|
||||
static uint8_t split_central_sensor_notify_func(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params,
|
||||
const void *data, uint16_t length) {
|
||||
if (!data) {
|
||||
LOG_DBG("[UNSUBSCRIBED]");
|
||||
params->value_handle = 0U;
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
LOG_DBG("[SENSOR NOTIFICATION] data %p length %u", data, length);
|
||||
|
||||
if (length < offsetof(struct sensor_event, channel_data)) {
|
||||
LOG_WRN("Ignoring sensor notify with insufficient data length (%d)", length);
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
struct sensor_event sensor_event;
|
||||
memcpy(&sensor_event, data, MIN(length, sizeof(sensor_event)));
|
||||
struct zmk_sensor_event ev = {
|
||||
.sensor_index = sensor_event.sensor_index,
|
||||
.channel_data_size = MIN(sensor_event.channel_data_size, ZMK_SENSOR_EVENT_MAX_CHANNELS),
|
||||
.timestamp = k_uptime_get()};
|
||||
|
||||
memcpy(ev.channel_data, sensor_event.channel_data,
|
||||
sizeof(struct zmk_sensor_channel_data) * sensor_event.channel_data_size);
|
||||
k_msgq_put(&peripheral_sensor_event_msgq, &ev, K_NO_WAIT);
|
||||
k_work_submit(&peripheral_sensor_event_work);
|
||||
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
static uint8_t split_central_notify_func(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params, const void *data,
|
||||
uint16_t length) {
|
||||
@@ -209,14 +258,8 @@ static uint8_t split_central_notify_func(struct bt_conn *conn,
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
static void split_central_subscribe(struct bt_conn *conn) {
|
||||
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);
|
||||
static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscribe_params *params) {
|
||||
int err = bt_gatt_subscribe(conn, params);
|
||||
switch (err) {
|
||||
case -EALREADY:
|
||||
LOG_DBG("[ALREADY SUBSCRIBED]");
|
||||
@@ -228,6 +271,8 @@ static void split_central_subscribe(struct bt_conn *conn) {
|
||||
LOG_ERR("Subscribe failed (err %d)", err);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
||||
@@ -250,9 +295,9 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
||||
}
|
||||
|
||||
LOG_DBG("[ATTRIBUTE] handle %u", attr->handle);
|
||||
const struct bt_uuid *chrc_uuid = ((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)) == 0) {
|
||||
if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID)) == 0) {
|
||||
LOG_DBG("Found position state characteristic");
|
||||
slot->discover_params.uuid = NULL;
|
||||
slot->discover_params.start_handle = attr->handle + 2;
|
||||
@@ -263,14 +308,33 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
||||
slot->subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
|
||||
slot->subscribe_params.notify = split_central_notify_func;
|
||||
slot->subscribe_params.value = BT_GATT_CCC_NOTIFY;
|
||||
split_central_subscribe(conn);
|
||||
} else if (bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
|
||||
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) == 0) {
|
||||
split_central_subscribe(conn, &slot->subscribe_params);
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
} else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_SENSOR_STATE_UUID)) ==
|
||||
0) {
|
||||
slot->discover_params.uuid = NULL;
|
||||
slot->discover_params.start_handle = attr->handle + 2;
|
||||
slot->discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||
|
||||
slot->sensor_subscribe_params.disc_params = &slot->sub_discover_params;
|
||||
slot->sensor_subscribe_params.end_handle = slot->discover_params.end_handle;
|
||||
slot->sensor_subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
|
||||
slot->sensor_subscribe_params.notify = split_central_sensor_notify_func;
|
||||
slot->sensor_subscribe_params.value = BT_GATT_CCC_NOTIFY;
|
||||
split_central_subscribe(conn, &slot->sensor_subscribe_params);
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
} else if (bt_uuid_cmp(chrc_uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_RUN_BEHAVIOR_UUID)) ==
|
||||
0) {
|
||||
LOG_DBG("Found run behavior handle");
|
||||
slot->discover_params.uuid = NULL;
|
||||
slot->discover_params.start_handle = attr->handle + 2;
|
||||
slot->run_behavior_handle = bt_gatt_attr_value_handle(attr);
|
||||
}
|
||||
|
||||
bool subscribed = (slot->run_behavior_handle && slot->subscribe_params.value_handle);
|
||||
bool subscribed = slot->run_behavior_handle && slot->subscribe_params.value_handle;
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
subscribed = subscribed && slot->sensor_subscribe_params.value_handle;
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user