diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/service.h similarity index 66% rename from app/include/zmk/split/bluetooth/service.h rename to app/include/zmk/split/service.h index 112cd5529424..303d2942c27c 100644 --- a/app/include/zmk/split/bluetooth/service.h +++ b/app/include/zmk/split/service.h @@ -10,6 +10,7 @@ #include #define ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN 9 +#define ZMK_SPLIT_POS_STATE_LEN 16 struct sensor_event { uint8_t sensor_index; @@ -30,8 +31,8 @@ struct zmk_split_run_behavior_payload { char behavior_dev[ZMK_SPLIT_RUN_BEHAVIOR_DEV_LEN]; } __packed; -int zmk_split_bt_position_pressed(uint8_t position); -int zmk_split_bt_position_released(uint8_t position); -int zmk_split_bt_sensor_triggered(uint8_t sensor_index, - const struct zmk_sensor_channel_data channel_data[], - size_t channel_data_size); +int zmk_split_position_pressed(uint8_t position); +int zmk_split_position_released(uint8_t position); +int zmk_split_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size); diff --git a/app/src/split/CMakeLists.txt b/app/src/split/CMakeLists.txt index 2e243e5c92f8..1205c026f782 100644 --- a/app/src/split/CMakeLists.txt +++ b/app/src/split/CMakeLists.txt @@ -3,6 +3,7 @@ if (CONFIG_ZMK_SPLIT_BLE AND (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL)) target_sources(app PRIVATE listener.c) + target_sources(app PRIVATE service.c) endif() if (CONFIG_ZMK_SPLIT_BLE) diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 3635322431c2..2070ff13f74f 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -23,7 +23,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include -#include +#include #include #include #include diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index 0072cf8c8357..0d231e661815 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -20,7 +20,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include -#include +#include #if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) #include @@ -43,10 +43,8 @@ static void split_svc_sensor_state_ccc(const struct bt_gatt_attr *attr, uint16_t } #endif /* ZMK_KEYMAP_HAS_SENSORS */ -#define POS_STATE_LEN 16 - static uint8_t num_of_positions = ZMK_KEYMAP_LEN; -static uint8_t position_state[POS_STATE_LEN]; +static uint8_t position_state[ZMK_SPLIT_POS_STATE_LEN]; static struct zmk_split_run_behavior_payload behavior_run_payload; @@ -162,116 +160,20 @@ BT_GATT_SERVICE_DEFINE( #endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS) ); -K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE); - -struct k_work_q service_work_q; - -K_MSGQ_DEFINE(position_state_msgq, sizeof(char[POS_STATE_LEN]), - CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); - -void send_position_state_callback(struct k_work *work) { - uint8_t state[POS_STATE_LEN]; - - while (k_msgq_get(&position_state_msgq, &state, K_NO_WAIT) == 0) { - int err = bt_gatt_notify(NULL, &split_svc.attrs[1], &state, sizeof(state)); - if (err) { - LOG_DBG("Error notifying %d", err); - } - } -}; - -K_WORK_DEFINE(service_position_notify_work, send_position_state_callback); - -int send_position_state() { - int err = k_msgq_put(&position_state_msgq, position_state, K_MSEC(100)); +void send_position_state_impl(uint8_t *state, int len) { + memcpy(position_state, state, MIN(len, sizeof(position_state))); + int err = bt_gatt_notify(NULL, &split_svc.attrs[1], state, len); if (err) { - switch (err) { - case -EAGAIN: { - LOG_WRN("Position state message queue full, popping first message and queueing again"); - uint8_t discarded_state[POS_STATE_LEN]; - k_msgq_get(&position_state_msgq, &discarded_state, K_NO_WAIT); - return send_position_state(); - } - default: - LOG_WRN("Failed to queue position state to send (%d)", err); - return err; - } + LOG_DBG("Error notifying %d", err); } - - k_work_submit_to_queue(&service_work_q, &service_position_notify_work); - - return 0; -} - -int zmk_split_bt_position_pressed(uint8_t position) { - WRITE_BIT(position_state[position / 8], position % 8, true); - return send_position_state(); -} - -int zmk_split_bt_position_released(uint8_t position) { - WRITE_BIT(position_state[position / 8], position % 8, false); - return send_position_state(); } #if ZMK_KEYMAP_HAS_SENSORS -K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event), - CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); - -void send_sensor_state_callback(struct k_work *work) { - while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) { - int err = bt_gatt_notify(NULL, &split_svc.attrs[8], &last_sensor_event, - sizeof(last_sensor_event)); - if (err) { - LOG_DBG("Error notifying %d", err); - } - } -}; - -K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback); - -int send_sensor_state(struct sensor_event ev) { - int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100)); +void send_sensor_state_impl(struct sensor_event *event, int len) { + memcpy(&last_sensor_event, event, MIN(len, sizeof(last_sensor_event))); + int err = bt_gatt_notify(NULL, &split_svc.attrs[8], event, len); if (err) { - // retry... - switch (err) { - case -EAGAIN: { - LOG_WRN("Sensor state message queue full, popping first message and queueing again"); - struct sensor_event discarded_state; - k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT); - return send_sensor_state(ev); - } - default: - LOG_WRN("Failed to queue sensor state to send (%d)", err); - return err; - } + LOG_DBG("Error notifying %d", err); } - - k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work); - return 0; -} - -int zmk_split_bt_sensor_triggered(uint8_t sensor_index, - const struct zmk_sensor_channel_data channel_data[], - size_t channel_data_size) { - if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) { - return -EINVAL; - } - - struct sensor_event ev = - (struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size}; - memcpy(ev.channel_data, channel_data, - channel_data_size * sizeof(struct zmk_sensor_channel_data)); - return send_sensor_state(ev); } #endif /* ZMK_KEYMAP_HAS_SENSORS */ - -int service_init(const struct device *_arg) { - static const struct k_work_queue_config queue_config = { - .name = "Split Peripheral Notification Queue"}; - k_work_queue_start(&service_work_q, service_q_stack, K_THREAD_STACK_SIZEOF(service_q_stack), - CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY, &queue_config); - - return 0; -} - -SYS_INIT(service_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/split/listener.c b/app/src/split/listener.c index 9b680d2c89cd..d7a144de57fa 100644 --- a/app/src/split/listener.c +++ b/app/src/split/listener.c @@ -7,7 +7,7 @@ #include #include -#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -23,17 +23,17 @@ int split_listener(const zmk_event_t *eh) { const struct zmk_position_state_changed *pos_ev; if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) { if (pos_ev->state) { - return zmk_split_bt_position_pressed(pos_ev->position); + return zmk_split_position_pressed(pos_ev->position); } else { - return zmk_split_bt_position_released(pos_ev->position); + return zmk_split_position_released(pos_ev->position); } } #if ZMK_KEYMAP_HAS_SENSORS const struct zmk_sensor_event *sensor_ev; if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) { - return zmk_split_bt_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data, - sensor_ev->channel_data_size); + return zmk_split_sensor_triggered(sensor_ev->sensor_index, sensor_ev->channel_data, + sensor_ev->channel_data_size); } #endif /* ZMK_KEYMAP_HAS_SENSORS */ return ZMK_EV_EVENT_BUBBLE; diff --git a/app/src/split/service.c b/app/src/split/service.c new file mode 100644 index 000000000000..e44121a32b12 --- /dev/null +++ b/app/src/split/service.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include +#include +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static uint8_t position_state[ZMK_SPLIT_POS_STATE_LEN]; +#if ZMK_KEYMAP_HAS_SENSORS +static struct sensor_event last_sensor_event; +#endif + +K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE); + +struct k_work_q service_work_q; + +K_MSGQ_DEFINE(position_state_msgq, sizeof(char[ZMK_SPLIT_POS_STATE_LEN]), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_position_state_callback(struct k_work *work) { + uint8_t state[ZMK_SPLIT_POS_STATE_LEN]; + + while (k_msgq_get(&position_state_msgq, &state, K_NO_WAIT) == 0) { + send_position_state_impl(&state, sizeof(state)); + } +}; + +K_WORK_DEFINE(service_position_notify_work, send_position_state_callback); + +int send_position_state() { + int err = k_msgq_put(&position_state_msgq, position_state, K_MSEC(100)); + if (err) { + switch (err) { + case -EAGAIN: { + LOG_WRN("Position state message queue full, popping first message and queueing again"); + uint8_t discarded_state[ZMK_SPLIT_POS_STATE_LEN]; + k_msgq_get(&position_state_msgq, &discarded_state, K_NO_WAIT); + return send_position_state(); + } + default: + LOG_WRN("Failed to queue position state to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&service_work_q, &service_position_notify_work); + + return 0; +} + +int zmk_split_position_pressed(uint8_t position) { + WRITE_BIT(position_state[position / 8], position % 8, true); + return send_position_state(); +} + +int zmk_split_position_released(uint8_t position) { + WRITE_BIT(position_state[position / 8], position % 8, false); + return send_position_state(); +} + +#if ZMK_KEYMAP_HAS_SENSORS +K_MSGQ_DEFINE(sensor_state_msgq, sizeof(struct sensor_event), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE, 4); + +void send_sensor_state_callback(struct k_work *work) { + while (k_msgq_get(&sensor_state_msgq, &last_sensor_event, K_NO_WAIT) == 0) { + send_sensor_state_impl(&last_sensor_event, sizeof(last_sensor_event)); + } +}; + +K_WORK_DEFINE(service_sensor_notify_work, send_sensor_state_callback); + +int send_sensor_state(struct sensor_event ev) { + int err = k_msgq_put(&sensor_state_msgq, &ev, K_MSEC(100)); + if (err) { + // retry... + switch (err) { + case -EAGAIN: { + LOG_WRN("Sensor state message queue full, popping first message and queueing again"); + struct sensor_event discarded_state; + k_msgq_get(&sensor_state_msgq, &discarded_state, K_NO_WAIT); + return send_sensor_state(ev); + } + default: + LOG_WRN("Failed to queue sensor state to send (%d)", err); + return err; + } + } + + k_work_submit_to_queue(&service_work_q, &service_sensor_notify_work); + return 0; +} + +int zmk_split_sensor_triggered(uint8_t sensor_index, + const struct zmk_sensor_channel_data channel_data[], + size_t channel_data_size) { + if (channel_data_size > ZMK_SENSOR_EVENT_MAX_CHANNELS) { + return -EINVAL; + } + + struct sensor_event ev = + (struct sensor_event){.sensor_index = sensor_index, .channel_data_size = channel_data_size}; + memcpy(ev.channel_data, channel_data, + channel_data_size * sizeof(struct zmk_sensor_channel_data)); + return send_sensor_state(ev); +} +#endif /* ZMK_KEYMAP_HAS_SENSORS */ + +int service_init(const struct device *_arg) { + static const struct k_work_queue_config queue_config = { + .name = "Split Peripheral Notification Queue"}; + k_work_queue_start(&service_work_q, service_q_stack, K_THREAD_STACK_SIZEOF(service_q_stack), + CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY, &queue_config); + + return 0; +} + +SYS_INIT(service_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);