-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathnRF52840_HrmBlePeripheral.ino
135 lines (114 loc) · 5.6 KB
/
nRF52840_HrmBlePeripheral.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Heart Rate Monitor BLE peripheral. Copyright (c) Thomas Amberg, FHNW
// Based on https://github.com/adafruit/Adafruit_nRF52_Arduino
// /tree/master/libraries/Bluefruit52Lib/examples/Peripheral
// Copyright (c) Adafruit.com, all rights reserved.
// Licensed under the MIT license, see LICENSE or
// https://choosealicense.com/licenses/mit/
#include "Adafruit_TinyUSB.h" // Fix https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/653
#include <bluefruit.h>
BLEDis deviceInfoService;
BLEBas batteryService;
// See https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Services/org.bluetooth.service.heart_rate.xml
// and https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.heart_rate_measurement.xml
// and https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.body_sensor_location.xml
BLEService heartRateMonitorService = BLEService(0x180D);
BLECharacteristic heartRateMeasurementCharacteristic = BLECharacteristic(0x2A37);
BLECharacteristic bodySensorLocationCharacteristic = BLECharacteristic(0x2A38);
BLECharacteristic heartRateControlPointCharacteristic = BLECharacteristic(0x2A39);
void connectedCallback(uint16_t connectionHandle) {
char centralName[32] = { 0 };
BLEConnection *connection = Bluefruit.Connection(connectionHandle);
connection->getPeerName(centralName, sizeof(centralName));
Serial.print(connectionHandle);
Serial.print(", connected to ");
Serial.print(centralName);
Serial.println();
}
void disconnectedCallback(uint16_t connectionHandle, uint8_t reason) {
Serial.print(connectionHandle);
Serial.print(" disconnected, reason = ");
Serial.println(reason); // see https://github.com/adafruit/Adafruit_nRF52_Arduino
// /blob/master/cores/nRF5/nordic/softdevice/s140_nrf52_6.1.1_API/include/ble_hci.h
Serial.println("Advertising ...");
}
void writeCallback(uint16_t connectionHandle, BLECharacteristic* characteristic, uint8_t* data, uint16_t len) {
if (characteristic->uuid == heartRateControlPointCharacteristic.uuid) {
Serial.print("Heater Rate Control Point 'Write', ");
Serial.println(data[0]); // TODO
}
}
void cccdCallback(uint16_t connectionHandle, BLECharacteristic* characteristic, uint16_t cccdValue) {
if (characteristic->uuid == heartRateMeasurementCharacteristic.uuid) {
Serial.print("Heart Rate Measurement 'Notify', ");
if (characteristic->notifyEnabled()) {
Serial.println("enabled");
} else {
Serial.println("disabled");
}
}
}
void setupHeartRateMonitorService() {
heartRateMonitorService.begin(); // Must be called before calling .begin() on its characteristics
heartRateMeasurementCharacteristic.setProperties(CHR_PROPS_NOTIFY);
heartRateMeasurementCharacteristic.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
heartRateMeasurementCharacteristic.setFixedLen(2);
heartRateMeasurementCharacteristic.setCccdWriteCallback(cccdCallback); // Optionally capture CCCD updates
heartRateMeasurementCharacteristic.begin();
uint8_t hrmData[2] = { 0b00000110, 0x40 }; // Use 8-bit values, sensor connected and detected
heartRateMeasurementCharacteristic.notify(hrmData, 2); // Use .notify instead of .write
bodySensorLocationCharacteristic.setProperties(CHR_PROPS_READ);
bodySensorLocationCharacteristic.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
bodySensorLocationCharacteristic.setFixedLen(1);
bodySensorLocationCharacteristic.begin();
bodySensorLocationCharacteristic.write8(0); // Sensor location 'Other'
heartRateControlPointCharacteristic.setProperties(CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP);
heartRateControlPointCharacteristic.setPermission(SECMODE_OPEN, SECMODE_OPEN);
heartRateControlPointCharacteristic.setFixedLen(1); // TODO: check HRM spec
heartRateControlPointCharacteristic.setWriteCallback(writeCallback, true);
heartRateControlPointCharacteristic.begin();
}
void startAdvertising() {
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addService(heartRateMonitorService);
Bluefruit.Advertising.addName();
// See https://developer.apple.com/library/content/qa/qa1931/_index.html
const int fastModeInterval = 32; // * 0.625 ms = 20 ms
const int slowModeInterval = 244; // * 0.625 ms = 152.5 ms
const int fastModeTimeout = 30; // s
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(fastModeInterval, slowModeInterval);
Bluefruit.Advertising.setFastTimeout(fastModeTimeout);
// 0 = continue advertising after fast mode, until connected
Bluefruit.Advertising.start(0);
Serial.println("Advertising ...");
}
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); } // only if usb connected
Serial.println("Setup");
Bluefruit.begin();
Bluefruit.setName("nRF52840");
Bluefruit.Periph.setConnectCallback(connectedCallback);
Bluefruit.Periph.setDisconnectCallback(disconnectedCallback);
deviceInfoService.setManufacturer("Adafruit Industries");
deviceInfoService.setModel("Feather nRF52840 Express");
deviceInfoService.begin();
batteryService.begin();
batteryService.write(100); // %
setupHeartRateMonitorService();
startAdvertising();
}
void loop() {
if (Bluefruit.connected()) {
int value = analogRead(A0);
uint8_t hrmData[2] = { 0b00000110, value };
if (heartRateMeasurementCharacteristic.notify(hrmData, sizeof(hrmData))) {
Serial.print("Heart rate = ");
Serial.println(value);
} else {
Serial.println("Notify not set, or not connected");
}
}
delay(1000); // ms
}