@@ -27,6 +27,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
27
27
#include <zmk/event_manager.h>
28
28
#include <zmk/events/position_state_changed.h>
29
29
#include <zmk/events/sensor_event.h>
30
+ #include <zmk/events/battery_state_changed.h>
30
31
#include <zmk/hid_indicators_types.h>
31
32
32
33
static int start_scanning (void );
@@ -47,6 +48,10 @@ struct peripheral_slot {
47
48
struct bt_gatt_subscribe_params sensor_subscribe_params ;
48
49
struct bt_gatt_discover_params sub_discover_params ;
49
50
uint16_t run_behavior_handle ;
51
+ #if IS_ENABLED (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING )
52
+ struct bt_gatt_subscribe_params batt_lvl_subscribe_params ;
53
+ struct bt_gatt_read_params batt_lvl_read_params ;
54
+ #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */
50
55
#if IS_ENABLED (CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS )
51
56
uint16_t update_hid_indicators ;
52
57
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
@@ -265,6 +270,110 @@ static uint8_t split_central_notify_func(struct bt_conn *conn,
265
270
return BT_GATT_ITER_CONTINUE ;
266
271
}
267
272
273
+ #if IS_ENABLED (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING )
274
+
275
+ static uint8_t peripheral_battery_levels [ZMK_SPLIT_BLE_PERIPHERAL_COUNT ] = {0 };
276
+
277
+ int zmk_split_get_peripheral_battery_level (uint8_t source , uint8_t * level ) {
278
+ if (source >= ARRAY_SIZE (peripheral_battery_levels )) {
279
+ return - EINVAL ;
280
+ }
281
+
282
+ if (peripherals [source ].state != PERIPHERAL_SLOT_STATE_CONNECTED ) {
283
+ return - ENOTCONN ;
284
+ }
285
+
286
+ * level = peripheral_battery_levels [source ];
287
+ return 0 ;
288
+ }
289
+
290
+ K_MSGQ_DEFINE (peripheral_batt_lvl_msgq , sizeof (struct zmk_peripheral_battery_state_changed ),
291
+ CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_QUEUE_SIZE , 4 );
292
+
293
+ void peripheral_batt_lvl_change_callback (struct k_work * work ) {
294
+ struct zmk_peripheral_battery_state_changed ev ;
295
+ while (k_msgq_get (& peripheral_batt_lvl_msgq , & ev , K_NO_WAIT ) == 0 ) {
296
+ LOG_DBG ("Triggering peripheral battery level change %u" , ev .state_of_charge );
297
+ peripheral_battery_levels [ev .source ] = ev .state_of_charge ;
298
+ ZMK_EVENT_RAISE (new_zmk_peripheral_battery_state_changed (ev ));
299
+ }
300
+ }
301
+
302
+ K_WORK_DEFINE (peripheral_batt_lvl_work , peripheral_batt_lvl_change_callback );
303
+
304
+ static uint8_t split_central_battery_level_notify_func (struct bt_conn * conn ,
305
+ struct bt_gatt_subscribe_params * params ,
306
+ const void * data , uint16_t length ) {
307
+ struct peripheral_slot * slot = peripheral_slot_for_conn (conn );
308
+
309
+ if (!slot ) {
310
+ LOG_ERR ("No peripheral state found for connection" );
311
+ return BT_GATT_ITER_CONTINUE ;
312
+ }
313
+
314
+ if (!data ) {
315
+ LOG_DBG ("[UNSUBSCRIBED]" );
316
+ params -> value_handle = 0U ;
317
+ return BT_GATT_ITER_STOP ;
318
+ }
319
+
320
+ if (length == 0 ) {
321
+ LOG_ERR ("Zero length battery notification received" );
322
+ return BT_GATT_ITER_CONTINUE ;
323
+ }
324
+
325
+ LOG_DBG ("[BATTERY LEVEL NOTIFICATION] data %p length %u" , data , length );
326
+ uint8_t battery_level = ((uint8_t * )data )[0 ];
327
+ LOG_DBG ("Battery level: %u" , battery_level );
328
+ struct zmk_peripheral_battery_state_changed ev = {
329
+ .source = peripheral_slot_index_for_conn (conn ), .state_of_charge = battery_level };
330
+ k_msgq_put (& peripheral_batt_lvl_msgq , & ev , K_NO_WAIT );
331
+ k_work_submit (& peripheral_batt_lvl_work );
332
+
333
+ return BT_GATT_ITER_CONTINUE ;
334
+ }
335
+
336
+ static uint8_t split_central_battery_level_read_func (struct bt_conn * conn , uint8_t err ,
337
+ struct bt_gatt_read_params * params ,
338
+ const void * data , uint16_t length ) {
339
+ if (err > 0 ) {
340
+ LOG_ERR ("Error during reading peripheral battery level: %u" , err );
341
+ return BT_GATT_ITER_STOP ;
342
+ }
343
+
344
+ struct peripheral_slot * slot = peripheral_slot_for_conn (conn );
345
+
346
+ if (!slot ) {
347
+ LOG_ERR ("No peripheral state found for connection" );
348
+ return BT_GATT_ITER_CONTINUE ;
349
+ }
350
+
351
+ if (!data ) {
352
+ LOG_DBG ("[READ COMPLETED]" );
353
+ return BT_GATT_ITER_STOP ;
354
+ }
355
+
356
+ LOG_DBG ("[BATTERY LEVEL READ] data %p length %u" , data , length );
357
+
358
+ if (length == 0 ) {
359
+ LOG_ERR ("Zero length battery notification received" );
360
+ return BT_GATT_ITER_CONTINUE ;
361
+ }
362
+
363
+ uint8_t battery_level = ((uint8_t * )data )[0 ];
364
+
365
+ LOG_DBG ("Battery level: %u" , battery_level );
366
+
367
+ struct zmk_peripheral_battery_state_changed ev = {
368
+ .source = peripheral_slot_index_for_conn (conn ), .state_of_charge = battery_level };
369
+ k_msgq_put (& peripheral_batt_lvl_msgq , & ev , K_NO_WAIT );
370
+ k_work_submit (& peripheral_batt_lvl_work );
371
+
372
+ return BT_GATT_ITER_CONTINUE ;
373
+ }
374
+
375
+ #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */
376
+
268
377
static int split_central_subscribe (struct bt_conn * conn , struct bt_gatt_subscribe_params * params ) {
269
378
int err = bt_gatt_subscribe (conn , params );
270
379
switch (err ) {
@@ -306,10 +415,6 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
306
415
307
416
if (bt_uuid_cmp (chrc_uuid , BT_UUID_DECLARE_128 (ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID )) == 0 ) {
308
417
LOG_DBG ("Found position state characteristic" );
309
- slot -> discover_params .uuid = NULL ;
310
- slot -> discover_params .start_handle = attr -> handle + 2 ;
311
- slot -> discover_params .type = BT_GATT_DISCOVER_CHARACTERISTIC ;
312
-
313
418
slot -> subscribe_params .disc_params = & slot -> sub_discover_params ;
314
419
slot -> subscribe_params .end_handle = slot -> discover_params .end_handle ;
315
420
slot -> subscribe_params .value_handle = bt_gatt_attr_value_handle (attr );
@@ -342,16 +447,37 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
342
447
LOG_DBG ("Found update HID indicators handle" );
343
448
slot -> update_hid_indicators = bt_gatt_attr_value_handle (attr );
344
449
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
450
+ #if IS_ENABLED (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING )
451
+ } else if (!bt_uuid_cmp (((struct bt_gatt_chrc * )attr -> user_data )-> uuid ,
452
+ BT_UUID_BAS_BATTERY_LEVEL )) {
453
+ LOG_DBG ("Found battery level characteristics" );
454
+ slot -> batt_lvl_subscribe_params .disc_params = & slot -> sub_discover_params ;
455
+ slot -> batt_lvl_subscribe_params .end_handle = slot -> discover_params .end_handle ;
456
+ slot -> batt_lvl_subscribe_params .value_handle = bt_gatt_attr_value_handle (attr );
457
+ slot -> batt_lvl_subscribe_params .notify = split_central_battery_level_notify_func ;
458
+ slot -> batt_lvl_subscribe_params .value = BT_GATT_CCC_NOTIFY ;
459
+ split_central_subscribe (conn , & slot -> batt_lvl_subscribe_params );
460
+
461
+ slot -> batt_lvl_read_params .func = split_central_battery_level_read_func ;
462
+ slot -> batt_lvl_read_params .handle_count = 1 ;
463
+ slot -> batt_lvl_read_params .single .handle = bt_gatt_attr_value_handle (attr );
464
+ slot -> batt_lvl_read_params .single .offset = 0 ;
465
+ bt_gatt_read (conn , & slot -> batt_lvl_read_params );
466
+ #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */
345
467
}
346
468
347
- bool subscribed = (slot -> run_behavior_handle && slot -> subscribe_params .value_handle );
469
+ bool subscribed = slot -> run_behavior_handle && slot -> subscribe_params .value_handle ;
470
+
348
471
#if ZMK_KEYMAP_HAS_SENSORS
349
472
subscribed = subscribed && slot -> sensor_subscribe_params .value_handle ;
350
473
#endif /* ZMK_KEYMAP_HAS_SENSORS */
351
474
352
475
#if IS_ENABLED (CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS )
353
476
subscribed = subscribed && slot -> update_hid_indicators ;
354
477
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
478
+ #if IS_ENABLED (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING )
479
+ subscribed = subscribed && slot -> batt_lvl_subscribe_params .value_handle ;
480
+ #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING) */
355
481
356
482
return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE ;
357
483
}
@@ -382,7 +508,6 @@ static uint8_t split_central_service_discovery_func(struct bt_conn *conn,
382
508
LOG_DBG ("Found split service" );
383
509
slot -> discover_params .uuid = NULL ;
384
510
slot -> discover_params .func = split_central_chrc_discovery_func ;
385
- slot -> discover_params .start_handle = attr -> handle + 1 ;
386
511
slot -> discover_params .type = BT_GATT_DISCOVER_CHARACTERISTIC ;
387
512
388
513
int err = bt_gatt_discover (conn , & slot -> discover_params );
@@ -605,6 +730,13 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) {
605
730
606
731
LOG_DBG ("Disconnected: %s (reason %d)" , addr , reason );
607
732
733
+ #if IS_ENABLED (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING )
734
+ struct zmk_peripheral_battery_state_changed ev = {
735
+ .source = peripheral_slot_index_for_conn (conn ), .state_of_charge = 0 };
736
+ k_msgq_put (& peripheral_batt_lvl_msgq , & ev , K_NO_WAIT );
737
+ k_work_submit (& peripheral_batt_lvl_work );
738
+ #endif // IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING)
739
+
608
740
err = release_peripheral_slot_for_conn (conn );
609
741
610
742
if (err < 0 ) {
0 commit comments