@@ -30,6 +30,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
30
30
#include <zmk/events/sensor_event.h>
31
31
#include <zmk/events/battery_state_changed.h>
32
32
#include <zmk/hid_indicators_types.h>
33
+ #include <zmk/physical_layouts.h>
33
34
34
35
static int start_scanning (void );
35
36
@@ -56,6 +57,7 @@ struct peripheral_slot {
56
57
#if IS_ENABLED (CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS )
57
58
uint16_t update_hid_indicators ;
58
59
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
60
+ uint16_t selected_physical_layout_handle ;
59
61
uint8_t position_state [POSITION_STATE_DATA_LEN ];
60
62
uint8_t changed_positions [POSITION_STATE_DATA_LEN ];
61
63
};
@@ -141,6 +143,7 @@ int release_peripheral_slot(int index) {
141
143
// Clean up previously discovered handles;
142
144
slot -> subscribe_params .value_handle = 0 ;
143
145
slot -> run_behavior_handle = 0 ;
146
+ slot -> selected_physical_layout_handle = 0 ;
144
147
#if IS_ENABLED (CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS )
145
148
slot -> update_hid_indicators = 0 ;
146
149
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
@@ -392,6 +395,46 @@ static int split_central_subscribe(struct bt_conn *conn, struct bt_gatt_subscrib
392
395
return err ;
393
396
}
394
397
398
+ static int update_peripheral_selected_layout (struct peripheral_slot * slot , uint8_t layout_idx ) {
399
+ if (slot -> state != PERIPHERAL_SLOT_STATE_CONNECTED ) {
400
+ return - ENOTCONN ;
401
+ }
402
+
403
+ if (slot -> selected_physical_layout_handle == 0 ) {
404
+ // It appears that sometimes the peripheral is considered connected
405
+ // before the GATT characteristics have been discovered. If this is
406
+ // the case, the selected_physical_layout_handle will not yet be set.
407
+ return - EAGAIN ;
408
+ }
409
+
410
+ if (bt_conn_get_security (slot -> conn ) < BT_SECURITY_L2 ) {
411
+ return - EAGAIN ;
412
+ }
413
+
414
+ int err = bt_gatt_write_without_response (slot -> conn , slot -> selected_physical_layout_handle ,
415
+ & layout_idx , sizeof (layout_idx ), true);
416
+
417
+ if (err < 0 ) {
418
+ LOG_ERR ("Failed to write physical layout index to peripheral (err %d)" , err );
419
+ }
420
+
421
+ return err ;
422
+ }
423
+
424
+ static void update_peripherals_selected_physical_layout (struct k_work * _work ) {
425
+ uint8_t layout_idx = zmk_physical_layouts_get_selected ();
426
+ for (int i = 0 ; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT ; i ++ ) {
427
+ if (peripherals [i ].state != PERIPHERAL_SLOT_STATE_CONNECTED ) {
428
+ continue ;
429
+ }
430
+
431
+ update_peripheral_selected_layout (& peripherals [i ], layout_idx );
432
+ }
433
+ }
434
+
435
+ K_WORK_DEFINE (update_peripherals_selected_layouts_work ,
436
+ update_peripherals_selected_physical_layout );
437
+
395
438
static uint8_t split_central_chrc_discovery_func (struct bt_conn * conn ,
396
439
const struct bt_gatt_attr * attr ,
397
440
struct bt_gatt_discover_params * params ) {
@@ -442,6 +485,11 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
442
485
slot -> discover_params .uuid = NULL ;
443
486
slot -> discover_params .start_handle = attr -> handle + 2 ;
444
487
slot -> run_behavior_handle = bt_gatt_attr_value_handle (attr );
488
+ } else if (!bt_uuid_cmp (((struct bt_gatt_chrc * )attr -> user_data )-> uuid ,
489
+ BT_UUID_DECLARE_128 (ZMK_SPLIT_BT_SELECT_PHYS_LAYOUT_UUID ))) {
490
+ LOG_DBG ("Found select physical layout handle" );
491
+ slot -> selected_physical_layout_handle = bt_gatt_attr_value_handle (attr );
492
+ k_work_submit (& update_peripherals_selected_layouts_work );
445
493
#if IS_ENABLED (CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS )
446
494
} else if (!bt_uuid_cmp (((struct bt_gatt_chrc * )attr -> user_data )-> uuid ,
447
495
BT_UUID_DECLARE_128 (ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID ))) {
@@ -467,7 +515,8 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
467
515
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */
468
516
}
469
517
470
- bool subscribed = slot -> run_behavior_handle && slot -> subscribe_params .value_handle ;
518
+ bool subscribed = slot -> run_behavior_handle && slot -> subscribe_params .value_handle &&
519
+ slot -> selected_physical_layout_handle ;
471
520
472
521
#if ZMK_KEYMAP_HAS_SENSORS
473
522
subscribed = subscribed && slot -> sensor_subscribe_params .value_handle ;
@@ -739,9 +788,30 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) {
739
788
start_scanning ();
740
789
}
741
790
791
+ static void split_central_security_changed (struct bt_conn * conn , bt_security_t level ,
792
+ enum bt_security_err err ) {
793
+ struct peripheral_slot * slot = peripheral_slot_for_conn (conn );
794
+ if (!slot || !slot -> selected_physical_layout_handle ) {
795
+ return ;
796
+ }
797
+
798
+ if (err > 0 ) {
799
+ LOG_DBG ("Skipping updating the physical layout for peripheral with security error" );
800
+ return ;
801
+ }
802
+
803
+ if (level < BT_SECURITY_L2 ) {
804
+ LOG_DBG ("Skipping updating the physical layout for peripheral with insufficient security" );
805
+ return ;
806
+ }
807
+
808
+ k_work_submit (& update_peripherals_selected_layouts_work );
809
+ }
810
+
742
811
static struct bt_conn_cb conn_callbacks = {
743
812
.connected = split_central_connected ,
744
813
.disconnected = split_central_disconnected ,
814
+ .security_changed = split_central_security_changed ,
745
815
};
746
816
747
817
K_THREAD_STACK_DEFINE (split_central_split_run_q_stack ,
@@ -898,3 +968,13 @@ static int zmk_split_bt_central_init(void) {
898
968
}
899
969
900
970
SYS_INIT (zmk_split_bt_central_init , APPLICATION , CONFIG_ZMK_BLE_INIT_PRIORITY );
971
+
972
+ static int zmk_split_bt_central_listener_cb (const zmk_event_t * eh ) {
973
+ if (as_zmk_physical_layout_selection_changed (eh )) {
974
+ k_work_submit (& update_peripherals_selected_layouts_work );
975
+ }
976
+ return ZMK_EV_EVENT_BUBBLE ;
977
+ }
978
+
979
+ ZMK_LISTENER (zmk_split_bt_central , zmk_split_bt_central_listener_cb );
980
+ ZMK_SUBSCRIPTION (zmk_split_bt_central , zmk_physical_layout_selection_changed );
0 commit comments