BLE Heart Rate Sample Program for HRM1017 which is using Nordic nRF51822 confirmed the connection of nRFToolbox on Android.

Dependencies:   BLE_API mbed nRF51822 color_pixels

Fork of BLE_HTM_HRM1017 by Switch Science

Committer:
YoshinoTaro
Date:
Sun Oct 16 14:25:59 2016 +0000
Revision:
11:d32f4f43161d
Parent:
10:8a67578c3ef0
Enable Heart Rate Sensor and PixelLeds;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
todotani 0:5e4210d108ac 1 #include "mbed.h"
ytsuboi 8:f753b4b022a8 2 #include "BLE.h"
YoshinoTaro 11:d32f4f43161d 3 #include "color_pixels.h"
YoshinoTaro 10:8a67578c3ef0 4 #include <math.h>
todotani 0:5e4210d108ac 5
YoshinoTaro 11:d32f4f43161d 6 #include "PulseSensor.h"
todotani 0:5e4210d108ac 7
YoshinoTaro 11:d32f4f43161d 8 #define NEED_DEBUG
YoshinoTaro 11:d32f4f43161d 9 #ifdef NEED_DEBUG
YoshinoTaro 10:8a67578c3ef0 10 #define DEBUG(...) { printf(__VA_ARGS__); }
todotani 0:5e4210d108ac 11 #else
todotani 0:5e4210d108ac 12 #define DEBUG(...) /* nothing */
YoshinoTaro 10:8a67578c3ef0 13 #endif
YoshinoTaro 10:8a67578c3ef0 14
todotani 0:5e4210d108ac 15
YoshinoTaro 10:8a67578c3ef0 16 const static char DEVICE_NAME[] = "mbed HRM1017";
todotani 2:daf2344afc28 17 static volatile bool triggerSensorPolling = false;
todotani 0:5e4210d108ac 18
YoshinoTaro 10:8a67578c3ef0 19
todotani 0:5e4210d108ac 20 BLEDevice ble;
YoshinoTaro 10:8a67578c3ef0 21
todotani 0:5e4210d108ac 22
YoshinoTaro 10:8a67578c3ef0 23 /* Heart Rate Service */
YoshinoTaro 10:8a67578c3ef0 24 static uint8_t hrmCounter = 100;
YoshinoTaro 10:8a67578c3ef0 25 static uint8_t bpm[2] = {0x00, hrmCounter};
YoshinoTaro 10:8a67578c3ef0 26 GattCharacteristic hrmChar(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR
YoshinoTaro 10:8a67578c3ef0 27 ,bpm, sizeof(bpm) ,sizeof(bpm)
YoshinoTaro 10:8a67578c3ef0 28 ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
YoshinoTaro 10:8a67578c3ef0 29 static uint8_t location = 0x05; /* Ear Lobe */
YoshinoTaro 10:8a67578c3ef0 30 GattCharacteristic hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR
YoshinoTaro 10:8a67578c3ef0 31 ,(uint8_t *)&location ,sizeof(location) ,sizeof(location)
YoshinoTaro 10:8a67578c3ef0 32 ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
YoshinoTaro 10:8a67578c3ef0 33 GattCharacteristic *hrmChars[] = {&hrmChar, &hrmLocation,};
YoshinoTaro 10:8a67578c3ef0 34 GattService hrmService(GattService::UUID_HEART_RATE_SERVICE
YoshinoTaro 10:8a67578c3ef0 35 ,hrmChars ,sizeof(hrmChars)/sizeof(GattCharacteristic *));
todotani 0:5e4210d108ac 36
todotani 0:5e4210d108ac 37
todotani 0:5e4210d108ac 38
todotani 0:5e4210d108ac 39 /* Battery Level Service */
YoshinoTaro 10:8a67578c3ef0 40 static uint8_t batt = 100;
YoshinoTaro 10:8a67578c3ef0 41 GattCharacteristic battLevel(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR
YoshinoTaro 10:8a67578c3ef0 42 ,(uint8_t *)&batt ,sizeof(batt) ,sizeof(batt)
YoshinoTaro 10:8a67578c3ef0 43 ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
YoshinoTaro 10:8a67578c3ef0 44 GattCharacteristic *battChars[] = {&battLevel,};
YoshinoTaro 10:8a67578c3ef0 45 GattService battService(GattService::UUID_BATTERY_SERVICE
YoshinoTaro 10:8a67578c3ef0 46 ,battChars ,sizeof(battChars)/sizeof(GattCharacteristic *));
YoshinoTaro 10:8a67578c3ef0 47
YoshinoTaro 10:8a67578c3ef0 48
todotani 0:5e4210d108ac 49
YoshinoTaro 10:8a67578c3ef0 50 /* Device Information service */
YoshinoTaro 10:8a67578c3ef0 51 static uint8_t deviceName[] = {'H', 'R', 'M', '1', '0', '1', '7'};
YoshinoTaro 10:8a67578c3ef0 52 GattCharacteristic deviceManufacturer(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR
YoshinoTaro 10:8a67578c3ef0 53 ,(uint8_t *)deviceName ,sizeof(deviceName) ,sizeof(deviceName)
YoshinoTaro 10:8a67578c3ef0 54 ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
YoshinoTaro 10:8a67578c3ef0 55 GattCharacteristic *devInfoChars[] = {&deviceManufacturer,};
YoshinoTaro 10:8a67578c3ef0 56 GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE
YoshinoTaro 10:8a67578c3ef0 57 ,devInfoChars ,sizeof(devInfoChars)/sizeof(GattCharacteristic *));
todotani 0:5e4210d108ac 58
YoshinoTaro 10:8a67578c3ef0 59
YoshinoTaro 10:8a67578c3ef0 60 static uint16_t uuid16_list[] = {
YoshinoTaro 10:8a67578c3ef0 61 GattService::UUID_HEART_RATE_SERVICE
YoshinoTaro 10:8a67578c3ef0 62 ,GattService::UUID_BATTERY_SERVICE
YoshinoTaro 10:8a67578c3ef0 63 ,GattService::UUID_DEVICE_INFORMATION_SERVICE
YoshinoTaro 10:8a67578c3ef0 64 };
YoshinoTaro 10:8a67578c3ef0 65
YoshinoTaro 10:8a67578c3ef0 66
todotani 0:5e4210d108ac 67 void updateServiceValues(void);
todotani 0:5e4210d108ac 68 static Gap::ConnectionParams_t connectionParams;
todotani 0:5e4210d108ac 69
YoshinoTaro 10:8a67578c3ef0 70 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
todotani 0:5e4210d108ac 71 {
mbed_tw_hoehoe 9:554af3c63d0c 72 DEBUG("Disconnected handle %u, reason %u\r\n", params->handle, params->reason);
ytsuboi 8:f753b4b022a8 73 DEBUG("Restarting the advertising process\r\n");
ytsuboi 8:f753b4b022a8 74 ble.gap().startAdvertising();
todotani 0:5e4210d108ac 75 }
todotani 0:5e4210d108ac 76
ytsuboi 8:f753b4b022a8 77 void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) //Mod
todotani 0:5e4210d108ac 78 {
ytsuboi 8:f753b4b022a8 79 DEBUG("connected. Got handle %u\r\n", params->handle);
todotani 0:5e4210d108ac 80
todotani 0:5e4210d108ac 81 connectionParams.slaveLatency = 1;
ytsuboi 8:f753b4b022a8 82 if (ble.gap().updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE) {
todotani 0:5e4210d108ac 83 DEBUG("failed to update connection paramter\r\n");
todotani 0:5e4210d108ac 84 }
todotani 0:5e4210d108ac 85 }
todotani 0:5e4210d108ac 86
todotani 2:daf2344afc28 87 void periodicCallback(void)
todotani 2:daf2344afc28 88 {
todotani 2:daf2344afc28 89 triggerSensorPolling = true;
todotani 2:daf2344afc28 90 }
todotani 2:daf2344afc28 91
YoshinoTaro 11:d32f4f43161d 92 ColorPixels pixels(6,8);
YoshinoTaro 11:d32f4f43161d 93 int ledfade = 0;
YoshinoTaro 11:d32f4f43161d 94 void pixelPattern(int n, uint8_t r, uint8_t g, uint8_t b);
YoshinoTaro 11:d32f4f43161d 95
YoshinoTaro 11:d32f4f43161d 96
todotani 0:5e4210d108ac 97 int main(void)
YoshinoTaro 11:d32f4f43161d 98 {
todotani 2:daf2344afc28 99 Ticker ticker;
todotani 2:daf2344afc28 100 ticker.attach(periodicCallback, 1);
YoshinoTaro 11:d32f4f43161d 101
ytsuboi 8:f753b4b022a8 102 DEBUG("Initialising the nRF51822\r\n");
todotani 0:5e4210d108ac 103 ble.init();
ytsuboi 8:f753b4b022a8 104 DEBUG("Init done\r\n");
ytsuboi 8:f753b4b022a8 105 ble.gap().onDisconnection(disconnectionCallback);
ytsuboi 8:f753b4b022a8 106 ble.gap().onConnection(onConnectionCallback);
todotani 0:5e4210d108ac 107
ytsuboi 8:f753b4b022a8 108 ble.gap().getPreferredConnectionParams(&connectionParams);
todotani 0:5e4210d108ac 109
todotani 0:5e4210d108ac 110 /* setup advertising */
ytsuboi 8:f753b4b022a8 111 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ytsuboi 8:f753b4b022a8 112 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list));
YoshinoTaro 10:8a67578c3ef0 113 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
ytsuboi 8:f753b4b022a8 114 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ytsuboi 8:f753b4b022a8 115 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ytsuboi 8:f753b4b022a8 116 ble.gap().setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
ytsuboi 8:f753b4b022a8 117 ble.gap().startAdvertising();
ytsuboi 8:f753b4b022a8 118 DEBUG("Start Advertising\r\n");
todotani 0:5e4210d108ac 119
YoshinoTaro 10:8a67578c3ef0 120 ble.gattServer().addService(hrmService);
ytsuboi 8:f753b4b022a8 121 ble.gattServer().addService(battService);
YoshinoTaro 10:8a67578c3ef0 122 ble.gattServer().addService(deviceInformationService);
ytsuboi 8:f753b4b022a8 123 DEBUG("Add Service\r\n");
YoshinoTaro 11:d32f4f43161d 124
YoshinoTaro 11:d32f4f43161d 125 initPulseSensor();
YoshinoTaro 11:d32f4f43161d 126
YoshinoTaro 11:d32f4f43161d 127 Ticker hrm_ticker;
YoshinoTaro 11:d32f4f43161d 128 hrm_ticker.attach(calcHeartRate, 0.02);
YoshinoTaro 11:d32f4f43161d 129
YoshinoTaro 11:d32f4f43161d 130 int counter = 0;
YoshinoTaro 11:d32f4f43161d 131 uint8_t cl = 193;
todotani 0:5e4210d108ac 132
todotani 2:daf2344afc28 133 while (true) {
todotani 2:daf2344afc28 134 if (triggerSensorPolling) {
todotani 2:daf2344afc28 135 triggerSensorPolling = false;
todotani 2:daf2344afc28 136 updateServiceValues();
todotani 2:daf2344afc28 137 } else {
todotani 2:daf2344afc28 138 ble.waitForEvent();
todotani 2:daf2344afc28 139 }
YoshinoTaro 11:d32f4f43161d 140 if (counter % 3 == 0) {
YoshinoTaro 11:d32f4f43161d 141 if (ledfade) {
YoshinoTaro 11:d32f4f43161d 142 --ledfade;
YoshinoTaro 11:d32f4f43161d 143 pixelPattern(ledfade, cl, cl, cl);
YoshinoTaro 11:d32f4f43161d 144 counter = 0;
YoshinoTaro 11:d32f4f43161d 145 }
YoshinoTaro 11:d32f4f43161d 146 }
YoshinoTaro 11:d32f4f43161d 147 ++counter;
todotani 0:5e4210d108ac 148 }
YoshinoTaro 11:d32f4f43161d 149
todotani 0:5e4210d108ac 150 }
todotani 0:5e4210d108ac 151
YoshinoTaro 11:d32f4f43161d 152
YoshinoTaro 11:d32f4f43161d 153
todotani 0:5e4210d108ac 154 void updateServiceValues(void)
todotani 0:5e4210d108ac 155 {
YoshinoTaro 10:8a67578c3ef0 156 /* Decrement the battery level. */
YoshinoTaro 10:8a67578c3ef0 157 batt <= 50 ? batt = 100 : batt--;
YoshinoTaro 10:8a67578c3ef0 158 ble.gattServer().write(battLevel.getValueAttribute().getHandle(), (uint8_t *)&batt, sizeof(batt));
todotani 0:5e4210d108ac 159
YoshinoTaro 10:8a67578c3ef0 160 /* Randomize the heart rate. */
YoshinoTaro 11:d32f4f43161d 161 // hrmCounter = (rand() % 150) + 30;
YoshinoTaro 11:d32f4f43161d 162 if (isQS()) {
YoshinoTaro 11:d32f4f43161d 163 hrmCounter = getBPM();
YoshinoTaro 11:d32f4f43161d 164 DEBUG("BPM: %d\r\n", hrmCounter);
YoshinoTaro 11:d32f4f43161d 165 ledfade = 5;
YoshinoTaro 11:d32f4f43161d 166 }
YoshinoTaro 11:d32f4f43161d 167
YoshinoTaro 10:8a67578c3ef0 168 bpm[1] = hrmCounter;
YoshinoTaro 10:8a67578c3ef0 169 ble.gattServer().write(hrmChar.getValueAttribute().getHandle(), bpm, sizeof(bpm));
todotani 0:5e4210d108ac 170 }
YoshinoTaro 11:d32f4f43161d 171
YoshinoTaro 11:d32f4f43161d 172
YoshinoTaro 11:d32f4f43161d 173 void pixelPattern(int n, uint8_t r, uint8_t g, uint8_t b) {
YoshinoTaro 11:d32f4f43161d 174
YoshinoTaro 11:d32f4f43161d 175 if (n < 0 || n > 4) return;
YoshinoTaro 11:d32f4f43161d 176
YoshinoTaro 11:d32f4f43161d 177 switch (n) {
YoshinoTaro 11:d32f4f43161d 178 case 4:
YoshinoTaro 11:d32f4f43161d 179 pixels.set_color(7, r, g, b);
YoshinoTaro 11:d32f4f43161d 180 pixels.set_color(6, r, g, b);
YoshinoTaro 11:d32f4f43161d 181 pixels.set_color(5, r, g, b);
YoshinoTaro 11:d32f4f43161d 182 pixels.set_color(4, r, g, b);
YoshinoTaro 11:d32f4f43161d 183 pixels.set_color(3, r, g, b);
YoshinoTaro 11:d32f4f43161d 184 pixels.set_color(2, r, g, b);
YoshinoTaro 11:d32f4f43161d 185 pixels.set_color(1, r, g, b);
YoshinoTaro 11:d32f4f43161d 186 pixels.set_color(0, r, g, b);
YoshinoTaro 11:d32f4f43161d 187 pixels.update();
YoshinoTaro 11:d32f4f43161d 188 break;
YoshinoTaro 11:d32f4f43161d 189 case 3:
YoshinoTaro 11:d32f4f43161d 190 pixels.set_color(7, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 191 pixels.set_color(6, r/2, g/2, b/2);
YoshinoTaro 11:d32f4f43161d 192 pixels.set_color(5, r*3/4, g*3/4, b*3/4);
YoshinoTaro 11:d32f4f43161d 193 pixels.set_color(4, r, g, b);
YoshinoTaro 11:d32f4f43161d 194 pixels.set_color(3, r, g, b);
YoshinoTaro 11:d32f4f43161d 195 pixels.set_color(2, r*3/4, g*3/4, b*3/4);
YoshinoTaro 11:d32f4f43161d 196 pixels.set_color(1, r/2, g/2, b/2);
YoshinoTaro 11:d32f4f43161d 197 pixels.set_color(0, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 198 pixels.update();
YoshinoTaro 11:d32f4f43161d 199 break;
YoshinoTaro 11:d32f4f43161d 200 case 2:
YoshinoTaro 11:d32f4f43161d 201 pixels.set_color(7, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 202 pixels.set_color(6, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 203 pixels.set_color(5, r/2, g/2, b/2);
YoshinoTaro 11:d32f4f43161d 204 pixels.set_color(4, r*3/4, g*3/4, b*3/4);
YoshinoTaro 11:d32f4f43161d 205 pixels.set_color(3, r*3/4, g*3/4, b*3/4);
YoshinoTaro 11:d32f4f43161d 206 pixels.set_color(2, r/2, g/2, b/2);
YoshinoTaro 11:d32f4f43161d 207 pixels.set_color(1, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 208 pixels.set_color(0, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 209 pixels.update();
YoshinoTaro 11:d32f4f43161d 210 break;
YoshinoTaro 11:d32f4f43161d 211 case 1:
YoshinoTaro 11:d32f4f43161d 212 pixels.set_color(7, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 213 pixels.set_color(6, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 214 pixels.set_color(5, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 215 pixels.set_color(4, r/2, g/2, b/4);
YoshinoTaro 11:d32f4f43161d 216 pixels.set_color(3, r/2, g/2, b/4);
YoshinoTaro 11:d32f4f43161d 217 pixels.set_color(2, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 218 pixels.set_color(1, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 219 pixels.set_color(0, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 220 pixels.update();
YoshinoTaro 11:d32f4f43161d 221 break;
YoshinoTaro 11:d32f4f43161d 222 case 0:
YoshinoTaro 11:d32f4f43161d 223 default:
YoshinoTaro 11:d32f4f43161d 224 pixels.set_color(7, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 225 pixels.set_color(6, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 226 pixels.set_color(5, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 227 pixels.set_color(4, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 228 pixels.set_color(3, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 229 pixels.set_color(2, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 230 pixels.set_color(1, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 231 pixels.set_color(0, 0, 0, 0);
YoshinoTaro 11:d32f4f43161d 232 pixels.update();
YoshinoTaro 11:d32f4f43161d 233 }
YoshinoTaro 11:d32f4f43161d 234 }