Skip to content

Commit a4a0a34

Browse files
committed
ble_hrm: use the health service event for HR updates
Stop maintaining a private HRM-manager subscription for BLE HRM sharing and instead ride on the existing PEBBLE_HEALTH_SERVICE_EVENT, which is already emitted by the health service while a workout is active (the only context in which Activity HR Sharing advertises). This removes a redundant 1 Hz poll and keeps the watch on a single HR data path. - Drop the hrm_manager_private.h dependency and the s_ble_hrm_session struct (which paired an EventServiceInfo with an HRMSessionRef); subscribe a single s_ble_hrm_event_info to PEBBLE_HEALTH_SERVICE_EVENT - Rename prv_ble_hrm_handle_hrm_data to prv_handle_health_event and read heart-rate data from HealthEventHeartRateUpdate instead of the raw HRM event - Remove the hrm_manager_subscribe_with_callback / sys_hrm_manager_unsubscribe calls from the start/stop paths - Update the unit tests: drop the now-unused subscribe/unsubscribe stubs and counters, point the event-service assertion at PEBBLE_HEALTH_SERVICE_EVENT, and rename the HR-event test/helper to *health_event Co-Authored-By: glm-5.2 Signed-off-by: Brint E. Kriebel <github@bekit.net>
1 parent f7df5aa commit a4a0a34

2 files changed

Lines changed: 39 additions & 92 deletions

File tree

src/fw/services/bluetooth/ble_hrm.c

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "popups/ble_hrm/ble_hrm_sharing_popup.h"
1515
#include "process_management/app_manager.h"
1616
#include "pbl/services/analytics/analytics.h"
17-
#include "pbl/services/hrm/hrm_manager_private.h"
1817
#include "pbl/services/regular_timer.h"
1918
#include "pbl/services/activity/activity.h"
2019
#include "pbl/services/activity/workout_service.h"
@@ -41,10 +40,7 @@ typedef struct BLEHRMSharingRequest {
4140
static bool s_ble_hrm_is_inited;
4241
static int s_ble_hrm_subscription_count;
4342
static RegularTimerInfo s_ble_hrm_timer;
44-
static struct {
45-
EventServiceInfo service_info;
46-
HRMSessionRef manager_session;
47-
} s_ble_hrm_session;
43+
static EventServiceInfo s_ble_hrm_event_info;
4844

4945
typedef enum {
5046
HrmSharingPermission_Unknown,
@@ -175,21 +171,21 @@ static size_t prv_copy_sharing_devices(BTDeviceInternal *devices_out,
175171
return (max_devices - ctx.slots_left);
176172
}
177173

178-
static void prv_ble_hrm_handle_hrm_data(PebbleEvent *e, void *context) {
174+
static void prv_handle_health_event(PebbleEvent *e, void *context) {
179175
if (!s_ble_hrm_is_inited) {
180176
return;
181177
}
182178
if (s_ble_hrm_subscription_count == 0) {
183179
return;
184180
}
185-
PBL_ASSERTN(e->type == PEBBLE_HRM_EVENT);
186-
const PebbleHRMEvent *const hrm_event = &e->hrm;
187-
if (hrm_event->event_type != HRMEvent_BPM) {
181+
PBL_ASSERTN(e->type == PEBBLE_HEALTH_SERVICE_EVENT);
182+
const PebbleHealthEvent *const health_event = &e->health_event;
183+
if (health_event->type != HealthEventHeartRateUpdate) {
188184
return;
189185
}
190186
const BleHrmServiceMeasurement measurement = {
191-
.bpm = hrm_event->bpm.bpm,
192-
.is_on_wrist = (hrm_event->bpm.quality >= HRMQuality_Worst),
187+
.bpm = health_event->data.heart_rate_update.current_bpm,
188+
.is_on_wrist = (health_event->data.heart_rate_update.quality >= HRMQuality_Worst),
193189
};
194190

195191
BTDeviceInternal sharing_to_devices[4];
@@ -200,22 +196,16 @@ static void prv_ble_hrm_handle_hrm_data(PebbleEvent *e, void *context) {
200196

201197
static void prv_start_hrm_kernel_main(void *unused) {
202198
PBL_LOG_INFO("BLE HRM sharing started");
203-
s_ble_hrm_session.service_info = (EventServiceInfo) {
204-
.type = PEBBLE_HRM_EVENT,
205-
.handler = prv_ble_hrm_handle_hrm_data,
199+
s_ble_hrm_event_info = (EventServiceInfo) {
200+
.type = PEBBLE_HEALTH_SERVICE_EVENT,
201+
.handler = prv_handle_health_event,
206202
};
207-
event_service_client_subscribe(&s_ble_hrm_session.service_info);
208-
s_ble_hrm_session.manager_session =
209-
hrm_manager_subscribe_with_callback(INSTALL_ID_INVALID, 1 /*update_interval_s*/,
210-
0 /*expire_s*/, HRMFeature_BPM, NULL, NULL);
211-
203+
event_service_client_subscribe(&s_ble_hrm_event_info);
212204
}
213205

214206
static void prv_stop_hrm_kernel_main(void *unused) {
215207
PBL_LOG_INFO("BLE HRM sharing stopped");
216-
sys_hrm_manager_unsubscribe(s_ble_hrm_session.manager_session);
217-
event_service_client_unsubscribe(&s_ble_hrm_session.service_info);
218-
208+
event_service_client_unsubscribe(&s_ble_hrm_event_info);
219209
}
220210

221211
static void prv_execute_on_kernel_main(CallbackEventCallback cb) {

tests/fw/services/bluetooth/test_ble_hrm.c

Lines changed: 27 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "pbl/services/bluetooth/ble_hrm.h"
55

66
#include "comm/ble/gap_le_connection.h"
7-
#include "pbl/services/hrm/hrm_manager_private.h"
7+
#include "pbl/services/activity/activity.h"
88

99
#include <bluetooth/hrm_service.h>
1010
#include <pbl/btutil/bt_device.h>
@@ -90,19 +90,6 @@ void ble_hrm_push_reminder_popup(void) {
9090
s_ble_hrm_push_reminder_popup_call_count++;
9191
}
9292

93-
static int s_hrm_manager_subscribe_with_callback_call_count;
94-
static HRMSessionRef s_last_session_ref;
95-
static HRMSessionRef s_next_session_ref;
96-
HRMSessionRef hrm_manager_subscribe_with_callback(AppInstallId app_id, uint32_t update_interval_s,
97-
uint16_t expire_s, HRMFeature features,
98-
HRMSubscriberCallback callback, void *context) {
99-
cl_assert_equal_p(NULL, callback); // we're using the event service
100-
cl_assert_equal_i(features, HRMFeature_BPM);
101-
++s_hrm_manager_subscribe_with_callback_call_count;
102-
s_last_session_ref = ++s_next_session_ref;
103-
return s_last_session_ref;
104-
}
105-
10693
static GAPLEConnection *s_connections[2];
10794

10895
GAPLEConnection *gap_le_connection_by_device(const BTDeviceInternal *device) {
@@ -140,18 +127,11 @@ bool sys_hrm_manager_is_hrm_present(void) {
140127
return true;
141128
}
142129

143-
static int s_sys_hrm_manager_unsubscribe_call_count;
144-
bool sys_hrm_manager_unsubscribe(HRMSessionRef session) {
145-
++s_sys_hrm_manager_unsubscribe_call_count;
146-
cl_assert_equal_i(session, s_last_session_ref);
147-
return true;
148-
}
149-
150130
////////////////////////////////////////////////////////////////////////////////////////////////////
151131
// Tests
152132

153133
static void prv_assert_event_service_subscribed(bool is_subscribed) {
154-
const EventServiceInfo *const info = fake_event_service_get_info(PEBBLE_HRM_EVENT);
134+
const EventServiceInfo *const info = fake_event_service_get_info(PEBBLE_HEALTH_SERVICE_EVENT);
155135
if (is_subscribed) {
156136
cl_assert(info->handler);
157137
} else {
@@ -163,10 +143,6 @@ void test_ble_hrm__cleanup(void) {
163143
ble_hrm_deinit();
164144

165145
prv_assert_event_service_subscribed(false);
166-
// hrm manager sub vs unsub calls should be the same, there should be no subscription any more
167-
// after de-initing:
168-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count,
169-
s_hrm_manager_subscribe_with_callback_call_count);
170146

171147
fake_pbl_malloc_check_net_allocs();
172148

@@ -192,16 +168,12 @@ void test_ble_hrm__initialize(void) {
192168
s_last_num_permitted_devices = 0;
193169
memset(s_last_permitted_devices, 0, sizeof(s_last_permitted_devices));
194170
s_bt_driver_hrm_service_enable_call_count = 0;
195-
s_hrm_manager_subscribe_with_callback_call_count = 0;
196-
s_sys_hrm_manager_unsubscribe_call_count = 0;
197171
s_bt_driver_hrm_service_handle_measurement_call_count = 0;
198172
s_ble_hrm_push_sharing_request_window_call_count = 0;
199173
s_ble_hrm_push_reminder_popup_call_count = 0;
200174
s_gap_le_slave_reconnect_hrm_restart_call_count = 0;
201175
s_gap_le_slave_reconnect_hrm_stop_call_count = 0;
202176
workout_service_stop_workout();
203-
s_last_session_ref = ~0;
204-
s_next_session_ref = 1234;
205177
s_last_disconnected = (BTDeviceInternal) {};
206178
s_last_sharing_request = NULL;
207179
s_last_ble_hrm_measurement = (BleHrmServiceMeasurement) {};
@@ -243,59 +215,48 @@ static void prv_assert_permissions_ui_and_respond(bool is_granted) {
243215
}
244216

245217
void test_ble_hrm__sub_unsub(void) {
246-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 0);
247-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 0);
248218
prv_assert_event_service_subscribed(false);
249219

250220
// Device A subscribes:
251221
bt_driver_cb_hrm_service_update_subscription(s_device_a, true);
252222

253-
// Expect HRM manager NOT to be subscribed to yet, need to grant permission first:
254-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 0);
223+
// Expect health event subscription NOT to be active yet, need to grant permission first:
255224
prv_assert_event_service_subscribed(false);
256225
cl_assert_equal_b(false, ble_hrm_is_sharing_to_connection(&s_conn_a));
257226

258227
// Expect permissions UI to be presented:
259228
prv_assert_permissions_ui_and_respond(true /* is_granted */);
260229

261-
// Expect HRM manager to be subscribed to:
262-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 1);
230+
// Expect health event subscription to be active:
263231
prv_assert_event_service_subscribed(true);
264232
cl_assert_equal_b(true, ble_hrm_is_sharing_to_connection(&s_conn_a));
265233

266234
// Device A subscribes again, should be a no-op, no new permissions prompt:
267235
bt_driver_cb_hrm_service_update_subscription(s_device_a, true);
268-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 1);
269-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 0);
236+
prv_assert_event_service_subscribed(true);
270237

271-
// Device B subscribes, shouldn't resubscribe to HRM manager, but should present a new
238+
// Device B subscribes, shouldn't resubscribe, but should present a new
272239
// permission prompt, because it's a different device:
273240
bt_driver_cb_hrm_service_update_subscription(s_device_b, true);
274241
cl_assert_equal_b(false, ble_hrm_is_sharing_to_connection(&s_conn_b));
275242
prv_assert_permissions_ui_and_respond(true /* is_granted */);
276243
cl_assert_equal_b(true, ble_hrm_is_sharing_to_connection(&s_conn_b));
277244
prv_assert_event_service_subscribed(true);
278-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 1);
279-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 0);
280245

281-
// Device A disconnects, shouldn't unsubscribe from HRM manager because A is still subscribed:
246+
// Device A disconnects, shouldn't unsubscribe because B is still subscribed:
282247
ble_hrm_handle_disconnection(&s_conn_a);
283248
cl_assert_equal_b(false, ble_hrm_is_sharing_to_connection(&s_conn_a));
284249
prv_assert_event_service_subscribed(true);
285-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 1);
286-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 0);
287250

288-
// Device B unsubscribes, expect to be unsubscribed from HRM manager, because there are no more
251+
// Device B unsubscribes, expect to unsubscribe because there are no more
289252
// devices subscribed to the BLE HRM service:
290253
bt_driver_cb_hrm_service_update_subscription(s_device_b, false);
291254
cl_assert_equal_b(false, ble_hrm_is_sharing_to_connection(&s_conn_a));
292255
prv_assert_event_service_subscribed(false);
293-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 1);
294256

295257
// Device B unsubscribes again, should be no-op
296258
bt_driver_cb_hrm_service_update_subscription(s_device_b, false);
297259
prv_assert_event_service_subscribed(false);
298-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count, 1);
299260
}
300261

301262
void test_ble_hrm__sub_unsub_resub(void) {
@@ -413,7 +374,7 @@ void test_ble_hrm__unsub_upon_deinit(void) {
413374
bt_driver_cb_hrm_service_update_subscription(s_device_a, true);
414375
prv_assert_permissions_ui_and_respond(true /* is_granted */);
415376

416-
// __cleanup() will do the deinit and also assert that there's no subscription to the HRM mgr.
377+
// __cleanup() will do the deinit and also assert that the event service is unsubscribed.
417378
}
418379

419380
// Test that we handle a races where a subscription/disconnection callback happens in after
@@ -423,30 +384,29 @@ void test_ble_hrm__sub_after_deinit(void) {
423384

424385
bt_driver_cb_hrm_service_update_subscription(s_device_a, true);
425386
prv_assert_event_service_subscribed(false);
426-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 0);
427387

428388
ble_hrm_handle_disconnection(&s_conn_a);
429389
prv_assert_event_service_subscribed(false);
430-
cl_assert_equal_i(s_hrm_manager_subscribe_with_callback_call_count, 0);
431390

432391
ble_hrm_init(); // reinit, __cleanup() will deinit again
433392
}
434393

435-
static void prv_put_and_assert_hrm_event(HRMEventType subtype, uint8_t bpm, HRMQuality quality,
436-
bool expect_bt_driver_cb, bool expected_is_on_wrist) {
394+
static void prv_put_and_assert_health_event(HealthEventType type, uint8_t bpm,
395+
HRMQuality quality, bool expect_bt_driver_cb,
396+
bool expected_is_on_wrist) {
437397
int call_count_before = s_bt_driver_hrm_service_handle_measurement_call_count;
438398

439-
PebbleEvent hrm_event = {
440-
.type = PEBBLE_HRM_EVENT,
441-
.hrm = {
442-
.event_type = subtype,
443-
.bpm = {
444-
.bpm = bpm,
399+
PebbleEvent event = {
400+
.type = PEBBLE_HEALTH_SERVICE_EVENT,
401+
.health_event = {
402+
.type = type,
403+
.data.heart_rate_update = {
404+
.current_bpm = bpm,
445405
.quality = quality,
446406
},
447407
},
448408
};
449-
event_put(&hrm_event);
409+
event_put(&event);
450410
fake_event_service_handle_last();
451411

452412
if (expect_bt_driver_cb) {
@@ -467,7 +427,7 @@ static void prv_put_workout_event(PebbleWorkoutEventType type) {
467427
fake_event_service_handle_last();
468428
}
469429

470-
void test_ble_hrm__handle_hrm_event(void) {
430+
void test_ble_hrm__handle_health_event(void) {
471431
bt_driver_cb_hrm_service_update_subscription(s_device_a, true);
472432
cl_assert_equal_i(0, s_bt_driver_hrm_service_handle_measurement_call_count);
473433
prv_assert_permissions_ui_and_respond(true /* is_granted */);
@@ -476,19 +436,19 @@ void test_ble_hrm__handle_hrm_event(void) {
476436
bt_driver_cb_hrm_service_update_subscription(s_device_b, true);
477437
prv_assert_permissions_ui_and_respond(false /* is_granted */);
478438

479-
prv_put_and_assert_hrm_event(HRMEvent_BPM, 80, HRMQuality_Excellent,
480-
true /* expect bt driver cb */, true /* expected_is_on_wrist */);
439+
prv_put_and_assert_health_event(HealthEventHeartRateUpdate, 80, HRMQuality_Excellent,
440+
true /* expect bt driver cb */, true /* expected_is_on_wrist */);
481441

482442
// Assert only device A is listed as "permitted device" and B is not:
483443
cl_assert_equal_i(1, s_last_num_permitted_devices);
484444
cl_assert_equal_m(&s_last_permitted_devices[0], s_device_a, sizeof(*s_device_a));
485445

486-
prv_put_and_assert_hrm_event(HRMEvent_BPM, 80, HRMQuality_OffWrist,
487-
true /* expect bt driver cb */, false /* expected_is_on_wrist */);
446+
prv_put_and_assert_health_event(HealthEventHeartRateUpdate, 80, HRMQuality_OffWrist,
447+
true /* expect bt driver cb */, false /* expected_is_on_wrist */);
488448

489-
// Ignore non-BPM event:
490-
prv_put_and_assert_hrm_event(HRMEvent_HRV, 80, HRMQuality_OffWrist,
491-
false /* expect bt driver cb */, false /* expected_is_on_wrist */);
449+
// Ignore non-heart-rate health event:
450+
prv_put_and_assert_health_event(HealthEventMovementUpdate, 0, HRMQuality_OffWrist,
451+
false /* expect bt driver cb */, false /* expected_is_on_wrist */);
492452
}
493453

494454
void test_ble_hrm__handle_ble_hrm_sharing_enabled_changes(void) {
@@ -557,9 +517,6 @@ void test_ble_hrm__workout_stop_stops_advert_and_disconnects_subscribers(void) {
557517

558518
cl_assert_equal_i(1, s_gap_le_slave_reconnect_hrm_stop_call_count);
559519
prv_assert_last_disconnected(s_device_a);
560-
// HRM manager should have been unsubscribed:
561-
cl_assert_equal_i(s_sys_hrm_manager_unsubscribe_call_count,
562-
s_hrm_manager_subscribe_with_callback_call_count);
563520
}
564521

565522
void test_ble_hrm__workout_stop_skips_non_sharers(void) {

0 commit comments

Comments
 (0)