Skip to content

Commit 68674ce

Browse files
committed
Add heart rate BLE service.
1 parent 3a3a141 commit 68674ce

9 files changed

Lines changed: 152 additions & 7 deletions

File tree

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ list(APPEND SOURCE_FILES
375375
components/ble/BatteryInformationService.cpp
376376
components/ble/ImmediateAlertService.cpp
377377
components/ble/ServiceDiscovery.cpp
378+
components/ble/HeartRateService.cpp
378379
components/firmwarevalidator/FirmwareValidator.cpp
379380
drivers/Cst816s.cpp
380381
FreeRTOS/port.c
@@ -464,6 +465,7 @@ set(INCLUDE_FILES
464465
components/ble/ImmediateAlertService.h
465466
components/ble/ServiceDiscovery.h
466467
components/ble/BleClient.h
468+
components/ble/HeartRateService.h.h
467469
drivers/Cst816s.h
468470
FreeRTOS/portmacro.h
469471
FreeRTOS/portmacro_cmsis.h
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include "HeartRateService.h"
2+
#include "components/heartrate/HeartRateController.h"
3+
#include "systemtask/SystemTask.h"
4+
5+
using namespace Pinetime::Controllers;
6+
7+
constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid;
8+
constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid;
9+
10+
namespace {
11+
int HeartRateServiceServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) {
12+
auto* heartRateService = static_cast<HeartRateService*>(arg);
13+
return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt);
14+
}
15+
}
16+
17+
// TODO Refactoring - remove dependency to SystemTask
18+
HeartRateService::HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController) :
19+
system{system},
20+
heartRateController{heartRateController},
21+
characteristicDefinition{
22+
{
23+
.uuid = (ble_uuid_t *) &heartRateMeasurementUuid,
24+
.access_cb = HeartRateServiceServiceCallback,
25+
.arg = this,
26+
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
27+
.val_handle = &heartRateMeasurementHandle
28+
},
29+
{
30+
0
31+
}
32+
},
33+
serviceDefinition{
34+
{
35+
/* Device Information Service */
36+
.type = BLE_GATT_SVC_TYPE_PRIMARY,
37+
.uuid = (ble_uuid_t *) &heartRateServiceUuid,
38+
.characteristics = characteristicDefinition
39+
},
40+
{
41+
0
42+
},
43+
}{
44+
// TODO refactor to prevent this loop dependency (service depends on controller and controller depends on service)
45+
heartRateController.SetService(this);
46+
}
47+
48+
void HeartRateService::Init() {
49+
int res = 0;
50+
res = ble_gatts_count_cfg(serviceDefinition);
51+
ASSERT(res == 0);
52+
53+
res = ble_gatts_add_svcs(serviceDefinition);
54+
ASSERT(res == 0);
55+
}
56+
57+
int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle,
58+
ble_gatt_access_ctxt *context) {
59+
if(attributeHandle == heartRateMeasurementHandle) {
60+
NRF_LOG_INFO("BATTERY : handle = %d", heartRateMeasurementHandle);
61+
static uint8_t batteryValue = heartRateController.HeartRate();
62+
63+
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
64+
65+
int res = os_mbuf_append(context->om, buffer, 2);
66+
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
67+
}
68+
return 0;
69+
}
70+
71+
void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) {
72+
uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value
73+
auto *om = ble_hs_mbuf_from_flat(buffer, 2);
74+
75+
uint16_t connectionHandle = system.nimble().connHandle();
76+
77+
if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) {
78+
return;
79+
}
80+
81+
ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om);
82+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
#define min // workaround: nimble's min/max macros conflict with libstdc++
3+
#define max
4+
#include <host/ble_gap.h>
5+
#undef max
6+
#undef min
7+
8+
namespace Pinetime {
9+
namespace System {
10+
class SystemTask;
11+
}
12+
namespace Controllers {
13+
class HeartRateController;
14+
class HeartRateService {
15+
public:
16+
HeartRateService(Pinetime::System::SystemTask &system, Controllers::HeartRateController& heartRateController);
17+
void Init();
18+
int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt *context);
19+
void OnNewHeartRateValue(uint8_t hearRateValue);
20+
21+
private:
22+
Pinetime::System::SystemTask &system;
23+
Controllers::HeartRateController& heartRateController;
24+
static constexpr uint16_t heartRateServiceId {0x180D};
25+
static constexpr uint16_t heartRateMeasurementId {0x2A37};
26+
27+
static constexpr ble_uuid16_t heartRateServiceUuid {
28+
.u {.type = BLE_UUID_TYPE_16},
29+
.value = heartRateServiceId
30+
};
31+
32+
static constexpr ble_uuid16_t heartRateMeasurementUuid {
33+
.u {.type = BLE_UUID_TYPE_16},
34+
.value = heartRateMeasurementId
35+
};
36+
37+
struct ble_gatt_chr_def characteristicDefinition[3];
38+
struct ble_gatt_svc_def serviceDefinition[2];
39+
40+
uint16_t heartRateMeasurementHandle;
41+
42+
};
43+
}
44+
}

src/components/ble/NimbleController.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
2222
DateTime& dateTimeController,
2323
Pinetime::Controllers::NotificationManager& notificationManager,
2424
Controllers::Battery& batteryController,
25-
Pinetime::Drivers::SpiNorFlash& spiNorFlash) :
25+
Pinetime::Drivers::SpiNorFlash& spiNorFlash,
26+
Controllers::HeartRateController& heartRateController) :
2627
systemTask{systemTask},
2728
bleController{bleController},
2829
dateTimeController{dateTimeController},
@@ -36,7 +37,8 @@ NimbleController::NimbleController(Pinetime::System::SystemTask& systemTask,
3637
musicService{systemTask},
3738
batteryInformationService{batteryController},
3839
immediateAlertService{systemTask, notificationManager},
39-
serviceDiscovery({&currentTimeClient, &alertNotificationClient}) {
40+
serviceDiscovery({&currentTimeClient, &alertNotificationClient}),
41+
heartRateService{systemTask, heartRateController} {
4042
}
4143

4244
int GAPEventCallback(struct ble_gap_event *event, void *arg) {
@@ -58,6 +60,7 @@ void NimbleController::Init() {
5860
dfuService.Init();
5961
batteryInformationService.Init();
6062
immediateAlertService.Init();
63+
heartRateService.Init();
6164
int res;
6265
res = ble_hs_util_ensure_addr(0);
6366
ASSERT(res == 0);

src/components/ble/NimbleController.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "ImmediateAlertService.h"
1818
#include "MusicService.h"
1919
#include "ServiceDiscovery.h"
20+
#include "HeartRateService.h"
2021

2122
namespace Pinetime {
2223
namespace Drivers {
@@ -37,7 +38,8 @@ namespace Pinetime {
3738
public:
3839
NimbleController(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::Ble& bleController,
3940
DateTime& dateTimeController, Pinetime::Controllers::NotificationManager& notificationManager,
40-
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash);
41+
Controllers::Battery& batteryController, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
42+
Controllers::HeartRateController& heartRateController);
4143
void Init();
4244
void StartAdvertising();
4345
int OnGAPEvent(ble_gap_event *event);
@@ -74,6 +76,7 @@ namespace Pinetime {
7476
MusicService musicService;
7577
BatteryInformationService batteryInformationService;
7678
ImmediateAlertService immediateAlertService;
79+
HeartRateService heartRateService;
7780

7881
uint8_t addrType; // 1 = Random, 0 = PUBLIC
7982
uint16_t connectionHandle = 0;

src/components/heartrate/HeartRateController.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ HeartRateController::HeartRateController(Pinetime::System::SystemTask &systemTas
1111

1212
void HeartRateController::Update(HeartRateController::States newState, uint8_t heartRate) {
1313
this->state = newState;
14-
this->heartRate = heartRate;
14+
if(this->heartRate != heartRate) {
15+
this->heartRate = heartRate;
16+
service->OnNewHeartRateValue(heartRate);
17+
}
1518
}
1619

1720
void HeartRateController::Start() {
@@ -32,3 +35,7 @@ void HeartRateController::SetHeartRateTask(Pinetime::Applications::HeartRateTask
3235
this->task = task;
3336
}
3437

38+
void HeartRateController::SetService(Pinetime::Controllers::HeartRateService *service) {
39+
this->service = service;
40+
}
41+

src/components/heartrate/HeartRateController.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <components/ble/HeartRateService.h>
45

56
namespace Pinetime {
67
namespace Applications {
@@ -24,11 +25,14 @@ namespace Pinetime {
2425
States State() const { return state; }
2526
uint8_t HeartRate() const { return heartRate; }
2627

28+
void SetService(Pinetime::Controllers::HeartRateService *service);
29+
2730
private:
2831
System::SystemTask& systemTask;
2932
Applications::HeartRateTask* task = nullptr;
3033
States state = States::Stopped;
3134
uint8_t heartRate = 0;
35+
Pinetime::Controllers::HeartRateService* service = nullptr;
3236
};
3337
}
3438
}

src/systemtask/SystemTask.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ SystemTask::SystemTask(Drivers::SpiMaster &spi, Drivers::St7789 &lcd,
4747
heartRateController{*this},
4848
bleController{bleController}, dateTimeController{dateTimeController},
4949
watchdog{}, watchdogView{watchdog}, notificationManager{notificationManager},
50-
nimbleController(*this, bleController,dateTimeController, notificationManager, batteryController, spiNorFlash),
51-
heartRateSensor{heartRateSensor}{
50+
heartRateSensor{heartRateSensor},
51+
nimbleController(*this, bleController,dateTimeController, notificationManager, batteryController, spiNorFlash, heartRateController) {
5252
systemTasksMsgQueue = xQueueCreate(10, 1);
5353
}
5454

src/systemtask/SystemTask.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ namespace Pinetime {
7474
Pinetime::Drivers::Watchdog watchdog;
7575
Pinetime::Drivers::WatchdogView watchdogView;
7676
Pinetime::Controllers::NotificationManager& notificationManager;
77-
Pinetime::Controllers::NimbleController nimbleController;
7877
Pinetime::Drivers::Hrs3300& heartRateSensor;
78+
Pinetime::Controllers::NimbleController nimbleController;
7979

8080
static constexpr uint8_t pinSpiSck = 2;
8181
static constexpr uint8_t pinSpiMosi = 3;

0 commit comments

Comments
 (0)