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
main.cpp@10:8a67578c3ef0, 2016-08-22 (annotated)
- Committer:
- YoshinoTaro
- Date:
- Mon Aug 22 06:12:27 2016 +0000
- Revision:
- 10:8a67578c3ef0
- Parent:
- 9:554af3c63d0c
- Child:
- 11:d32f4f43161d
BLE Heart Rate Sample Program for HRM1017 which is using Nordic nRF51822 confirmed the connection of nRFToolbox on Android.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
todotani | 0:5e4210d108ac | 1 | #include "mbed.h" |
ytsuboi | 8:f753b4b022a8 | 2 | #include "BLE.h" |
YoshinoTaro | 10:8a67578c3ef0 | 3 | #include <math.h> |
todotani | 0:5e4210d108ac | 4 | |
todotani | 0:5e4210d108ac | 5 | |
YoshinoTaro | 10:8a67578c3ef0 | 6 | #define NEED_DEBUG 1 |
YoshinoTaro | 10:8a67578c3ef0 | 7 | #if NEED_DEBUG |
YoshinoTaro | 10:8a67578c3ef0 | 8 | #define DEBUG(...) { printf(__VA_ARGS__); } |
todotani | 0:5e4210d108ac | 9 | #else |
todotani | 0:5e4210d108ac | 10 | #define DEBUG(...) /* nothing */ |
YoshinoTaro | 10:8a67578c3ef0 | 11 | #endif |
YoshinoTaro | 10:8a67578c3ef0 | 12 | |
todotani | 0:5e4210d108ac | 13 | |
YoshinoTaro | 10:8a67578c3ef0 | 14 | const static char DEVICE_NAME[] = "mbed HRM1017"; |
todotani | 2:daf2344afc28 | 15 | static volatile bool triggerSensorPolling = false; |
todotani | 0:5e4210d108ac | 16 | |
YoshinoTaro | 10:8a67578c3ef0 | 17 | |
todotani | 0:5e4210d108ac | 18 | BLEDevice ble; |
YoshinoTaro | 10:8a67578c3ef0 | 19 | |
todotani | 0:5e4210d108ac | 20 | |
YoshinoTaro | 10:8a67578c3ef0 | 21 | /* Heart Rate Service */ |
YoshinoTaro | 10:8a67578c3ef0 | 22 | static uint8_t hrmCounter = 100; |
YoshinoTaro | 10:8a67578c3ef0 | 23 | static uint8_t bpm[2] = {0x00, hrmCounter}; |
YoshinoTaro | 10:8a67578c3ef0 | 24 | GattCharacteristic hrmChar(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR |
YoshinoTaro | 10:8a67578c3ef0 | 25 | ,bpm, sizeof(bpm) ,sizeof(bpm) |
YoshinoTaro | 10:8a67578c3ef0 | 26 | ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); |
YoshinoTaro | 10:8a67578c3ef0 | 27 | static uint8_t location = 0x05; /* Ear Lobe */ |
YoshinoTaro | 10:8a67578c3ef0 | 28 | GattCharacteristic hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR |
YoshinoTaro | 10:8a67578c3ef0 | 29 | ,(uint8_t *)&location ,sizeof(location) ,sizeof(location) |
YoshinoTaro | 10:8a67578c3ef0 | 30 | ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
YoshinoTaro | 10:8a67578c3ef0 | 31 | GattCharacteristic *hrmChars[] = {&hrmChar, &hrmLocation,}; |
YoshinoTaro | 10:8a67578c3ef0 | 32 | GattService hrmService(GattService::UUID_HEART_RATE_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 33 | ,hrmChars ,sizeof(hrmChars)/sizeof(GattCharacteristic *)); |
todotani | 0:5e4210d108ac | 34 | |
todotani | 0:5e4210d108ac | 35 | |
todotani | 0:5e4210d108ac | 36 | |
todotani | 0:5e4210d108ac | 37 | /* Battery Level Service */ |
YoshinoTaro | 10:8a67578c3ef0 | 38 | static uint8_t batt = 100; |
YoshinoTaro | 10:8a67578c3ef0 | 39 | GattCharacteristic battLevel(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR |
YoshinoTaro | 10:8a67578c3ef0 | 40 | ,(uint8_t *)&batt ,sizeof(batt) ,sizeof(batt) |
YoshinoTaro | 10:8a67578c3ef0 | 41 | ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); |
YoshinoTaro | 10:8a67578c3ef0 | 42 | GattCharacteristic *battChars[] = {&battLevel,}; |
YoshinoTaro | 10:8a67578c3ef0 | 43 | GattService battService(GattService::UUID_BATTERY_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 44 | ,battChars ,sizeof(battChars)/sizeof(GattCharacteristic *)); |
YoshinoTaro | 10:8a67578c3ef0 | 45 | |
YoshinoTaro | 10:8a67578c3ef0 | 46 | |
todotani | 0:5e4210d108ac | 47 | |
YoshinoTaro | 10:8a67578c3ef0 | 48 | /* Device Information service */ |
YoshinoTaro | 10:8a67578c3ef0 | 49 | static uint8_t deviceName[] = {'H', 'R', 'M', '1', '0', '1', '7'}; |
YoshinoTaro | 10:8a67578c3ef0 | 50 | GattCharacteristic deviceManufacturer(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR |
YoshinoTaro | 10:8a67578c3ef0 | 51 | ,(uint8_t *)deviceName ,sizeof(deviceName) ,sizeof(deviceName) |
YoshinoTaro | 10:8a67578c3ef0 | 52 | ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
YoshinoTaro | 10:8a67578c3ef0 | 53 | GattCharacteristic *devInfoChars[] = {&deviceManufacturer,}; |
YoshinoTaro | 10:8a67578c3ef0 | 54 | GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 55 | ,devInfoChars ,sizeof(devInfoChars)/sizeof(GattCharacteristic *)); |
todotani | 0:5e4210d108ac | 56 | |
YoshinoTaro | 10:8a67578c3ef0 | 57 | |
YoshinoTaro | 10:8a67578c3ef0 | 58 | static uint16_t uuid16_list[] = { |
YoshinoTaro | 10:8a67578c3ef0 | 59 | GattService::UUID_HEART_RATE_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 60 | ,GattService::UUID_BATTERY_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 61 | ,GattService::UUID_DEVICE_INFORMATION_SERVICE |
YoshinoTaro | 10:8a67578c3ef0 | 62 | }; |
YoshinoTaro | 10:8a67578c3ef0 | 63 | |
YoshinoTaro | 10:8a67578c3ef0 | 64 | |
todotani | 0:5e4210d108ac | 65 | void updateServiceValues(void); |
todotani | 0:5e4210d108ac | 66 | static Gap::ConnectionParams_t connectionParams; |
todotani | 0:5e4210d108ac | 67 | |
YoshinoTaro | 10:8a67578c3ef0 | 68 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) |
todotani | 0:5e4210d108ac | 69 | { |
mbed_tw_hoehoe | 9:554af3c63d0c | 70 | DEBUG("Disconnected handle %u, reason %u\r\n", params->handle, params->reason); |
ytsuboi | 8:f753b4b022a8 | 71 | DEBUG("Restarting the advertising process\r\n"); |
ytsuboi | 8:f753b4b022a8 | 72 | ble.gap().startAdvertising(); |
todotani | 0:5e4210d108ac | 73 | } |
todotani | 0:5e4210d108ac | 74 | |
ytsuboi | 8:f753b4b022a8 | 75 | void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) //Mod |
todotani | 0:5e4210d108ac | 76 | { |
ytsuboi | 8:f753b4b022a8 | 77 | DEBUG("connected. Got handle %u\r\n", params->handle); |
todotani | 0:5e4210d108ac | 78 | |
todotani | 0:5e4210d108ac | 79 | connectionParams.slaveLatency = 1; |
ytsuboi | 8:f753b4b022a8 | 80 | if (ble.gap().updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE) { |
todotani | 0:5e4210d108ac | 81 | DEBUG("failed to update connection paramter\r\n"); |
todotani | 0:5e4210d108ac | 82 | } |
todotani | 0:5e4210d108ac | 83 | } |
todotani | 0:5e4210d108ac | 84 | |
todotani | 2:daf2344afc28 | 85 | void periodicCallback(void) |
todotani | 2:daf2344afc28 | 86 | { |
todotani | 2:daf2344afc28 | 87 | triggerSensorPolling = true; |
todotani | 2:daf2344afc28 | 88 | } |
todotani | 2:daf2344afc28 | 89 | |
todotani | 0:5e4210d108ac | 90 | int main(void) |
YoshinoTaro | 10:8a67578c3ef0 | 91 | { |
todotani | 2:daf2344afc28 | 92 | Ticker ticker; |
todotani | 2:daf2344afc28 | 93 | ticker.attach(periodicCallback, 1); |
todotani | 2:daf2344afc28 | 94 | |
ytsuboi | 8:f753b4b022a8 | 95 | DEBUG("Initialising the nRF51822\r\n"); |
todotani | 0:5e4210d108ac | 96 | ble.init(); |
ytsuboi | 8:f753b4b022a8 | 97 | DEBUG("Init done\r\n"); |
ytsuboi | 8:f753b4b022a8 | 98 | ble.gap().onDisconnection(disconnectionCallback); |
ytsuboi | 8:f753b4b022a8 | 99 | ble.gap().onConnection(onConnectionCallback); |
todotani | 0:5e4210d108ac | 100 | |
ytsuboi | 8:f753b4b022a8 | 101 | ble.gap().getPreferredConnectionParams(&connectionParams); |
todotani | 0:5e4210d108ac | 102 | |
todotani | 0:5e4210d108ac | 103 | /* setup advertising */ |
ytsuboi | 8:f753b4b022a8 | 104 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
ytsuboi | 8:f753b4b022a8 | 105 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list)); |
YoshinoTaro | 10:8a67578c3ef0 | 106 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); |
ytsuboi | 8:f753b4b022a8 | 107 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
ytsuboi | 8:f753b4b022a8 | 108 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
ytsuboi | 8:f753b4b022a8 | 109 | ble.gap().setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */ |
ytsuboi | 8:f753b4b022a8 | 110 | ble.gap().startAdvertising(); |
ytsuboi | 8:f753b4b022a8 | 111 | DEBUG("Start Advertising\r\n"); |
todotani | 0:5e4210d108ac | 112 | |
YoshinoTaro | 10:8a67578c3ef0 | 113 | ble.gattServer().addService(hrmService); |
ytsuboi | 8:f753b4b022a8 | 114 | ble.gattServer().addService(battService); |
YoshinoTaro | 10:8a67578c3ef0 | 115 | ble.gattServer().addService(deviceInformationService); |
ytsuboi | 8:f753b4b022a8 | 116 | DEBUG("Add Service\r\n"); |
todotani | 0:5e4210d108ac | 117 | |
todotani | 2:daf2344afc28 | 118 | while (true) { |
todotani | 2:daf2344afc28 | 119 | if (triggerSensorPolling) { |
todotani | 2:daf2344afc28 | 120 | triggerSensorPolling = false; |
todotani | 2:daf2344afc28 | 121 | updateServiceValues(); |
todotani | 2:daf2344afc28 | 122 | } else { |
todotani | 2:daf2344afc28 | 123 | ble.waitForEvent(); |
todotani | 2:daf2344afc28 | 124 | } |
todotani | 0:5e4210d108ac | 125 | } |
todotani | 0:5e4210d108ac | 126 | } |
todotani | 0:5e4210d108ac | 127 | |
todotani | 0:5e4210d108ac | 128 | void updateServiceValues(void) |
todotani | 0:5e4210d108ac | 129 | { |
YoshinoTaro | 10:8a67578c3ef0 | 130 | /* Decrement the battery level. */ |
YoshinoTaro | 10:8a67578c3ef0 | 131 | batt <= 50 ? batt = 100 : batt--; |
YoshinoTaro | 10:8a67578c3ef0 | 132 | ble.gattServer().write(battLevel.getValueAttribute().getHandle(), (uint8_t *)&batt, sizeof(batt)); |
todotani | 0:5e4210d108ac | 133 | |
YoshinoTaro | 10:8a67578c3ef0 | 134 | /* Randomize the heart rate. */ |
YoshinoTaro | 10:8a67578c3ef0 | 135 | hrmCounter = (rand() % 150) + 30; |
YoshinoTaro | 10:8a67578c3ef0 | 136 | bpm[1] = hrmCounter; |
YoshinoTaro | 10:8a67578c3ef0 | 137 | ble.gattServer().write(hrmChar.getValueAttribute().getHandle(), bpm, sizeof(bpm)); |
todotani | 0:5e4210d108ac | 138 | } |