BLE heartRate demo with security

Dependencies:   BLE_API mbed nRF51822

Committer:
sunsmile2015
Date:
Wed Jun 03 09:11:21 2015 +0000
Revision:
2:2d9d4b271af8
1.add comment; 2.add heartRate service with security; 3.print passkey as ASCII

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sunsmile2015 2:2d9d4b271af8 1 /* mbed Microcontroller Library
sunsmile2015 2:2d9d4b271af8 2 * Copyright (c) 2006-2013 ARM Limited
sunsmile2015 2:2d9d4b271af8 3 *
sunsmile2015 2:2d9d4b271af8 4 * Licensed under the Apache License, Version 2.0 (the "License");
sunsmile2015 2:2d9d4b271af8 5 * you may not use this file except in compliance with the License.
sunsmile2015 2:2d9d4b271af8 6 * You may obtain a copy of the License at
sunsmile2015 2:2d9d4b271af8 7 *
sunsmile2015 2:2d9d4b271af8 8 * http://www.apache.org/licenses/LICENSE-2.0
sunsmile2015 2:2d9d4b271af8 9 *
sunsmile2015 2:2d9d4b271af8 10 * Unless required by applicable law or agreed to in writing, software
sunsmile2015 2:2d9d4b271af8 11 * distributed under the License is distributed on an "AS IS" BASIS,
sunsmile2015 2:2d9d4b271af8 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
sunsmile2015 2:2d9d4b271af8 13 * See the License for the specific language governing permissions and
sunsmile2015 2:2d9d4b271af8 14 * limitations under the License.
sunsmile2015 2:2d9d4b271af8 15 */
sunsmile2015 2:2d9d4b271af8 16
sunsmile2015 2:2d9d4b271af8 17 #ifndef __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__
sunsmile2015 2:2d9d4b271af8 18 #define __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__
sunsmile2015 2:2d9d4b271af8 19
sunsmile2015 2:2d9d4b271af8 20 #include "BLEDevice.h"
sunsmile2015 2:2d9d4b271af8 21
sunsmile2015 2:2d9d4b271af8 22 /**
sunsmile2015 2:2d9d4b271af8 23 * @class HeartRateSecService
sunsmile2015 2:2d9d4b271af8 24 * @brief BLE Service for HeartRate. This BLE Service contains the location of the sensor, the heartrate in beats per minute. <br>
sunsmile2015 2:2d9d4b271af8 25 * Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml <br>
sunsmile2015 2:2d9d4b271af8 26 * HRM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml <br>
sunsmile2015 2:2d9d4b271af8 27 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml
sunsmile2015 2:2d9d4b271af8 28 */
sunsmile2015 2:2d9d4b271af8 29 class HeartRateSecService {
sunsmile2015 2:2d9d4b271af8 30 public:
sunsmile2015 2:2d9d4b271af8 31 /**
sunsmile2015 2:2d9d4b271af8 32 * @enum SensorLocation
sunsmile2015 2:2d9d4b271af8 33 * @brief Location of HeartRate sensor on body.
sunsmile2015 2:2d9d4b271af8 34 */
sunsmile2015 2:2d9d4b271af8 35 enum {
sunsmile2015 2:2d9d4b271af8 36 LOCATION_OTHER = 0, /*!< Other Location */
sunsmile2015 2:2d9d4b271af8 37 LOCATION_CHEST, /*!< Chest */
sunsmile2015 2:2d9d4b271af8 38 LOCATION_WRIST, /*!< Wrist */
sunsmile2015 2:2d9d4b271af8 39 LOCATION_FINGER, /*!< Finger */
sunsmile2015 2:2d9d4b271af8 40 LOCATION_HAND, /*!< Hand */
sunsmile2015 2:2d9d4b271af8 41 LOCATION_EAR_LOBE, /*!< Earlobe */
sunsmile2015 2:2d9d4b271af8 42 LOCATION_FOOT, /*!< Foot */
sunsmile2015 2:2d9d4b271af8 43 };
sunsmile2015 2:2d9d4b271af8 44
sunsmile2015 2:2d9d4b271af8 45 public:
sunsmile2015 2:2d9d4b271af8 46 /**
sunsmile2015 2:2d9d4b271af8 47 * @brief Constructor with 8bit HRM Counter value.
sunsmile2015 2:2d9d4b271af8 48 *
sunsmile2015 2:2d9d4b271af8 49 * @param[ref] _ble
sunsmile2015 2:2d9d4b271af8 50 * Reference to the underlying BLEDevice.
sunsmile2015 2:2d9d4b271af8 51 * @param[in] hrmCounter (8-bit)
sunsmile2015 2:2d9d4b271af8 52 * initial value for the hrm counter.
sunsmile2015 2:2d9d4b271af8 53 * @param[in] location
sunsmile2015 2:2d9d4b271af8 54 * Sensor's location.
sunsmile2015 2:2d9d4b271af8 55 */
sunsmile2015 2:2d9d4b271af8 56 HeartRateSecService(BLEDevice &_ble, uint8_t hrmCounter, uint8_t location) :
sunsmile2015 2:2d9d4b271af8 57 ble(_ble),
sunsmile2015 2:2d9d4b271af8 58 valueBytes(hrmCounter),
sunsmile2015 2:2d9d4b271af8 59 hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
sunsmile2015 2:2d9d4b271af8 60 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
sunsmile2015 2:2d9d4b271af8 61 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
sunsmile2015 2:2d9d4b271af8 62 hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
sunsmile2015 2:2d9d4b271af8 63 controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
sunsmile2015 2:2d9d4b271af8 64 setupService();
sunsmile2015 2:2d9d4b271af8 65 }
sunsmile2015 2:2d9d4b271af8 66
sunsmile2015 2:2d9d4b271af8 67 /**
sunsmile2015 2:2d9d4b271af8 68 * @brief Constructor with a 16-bit HRM Counter value.
sunsmile2015 2:2d9d4b271af8 69 *
sunsmile2015 2:2d9d4b271af8 70 * @param[in] _ble
sunsmile2015 2:2d9d4b271af8 71 * Reference to the underlying BLEDevice.
sunsmile2015 2:2d9d4b271af8 72 * @param[in] hrmCounter (8-bit)
sunsmile2015 2:2d9d4b271af8 73 * initial value for the hrm counter.
sunsmile2015 2:2d9d4b271af8 74 * @param[in] location
sunsmile2015 2:2d9d4b271af8 75 * Sensor's location.
sunsmile2015 2:2d9d4b271af8 76 */
sunsmile2015 2:2d9d4b271af8 77 HeartRateSecService(BLEDevice &_ble, uint16_t hrmCounter, uint8_t location) :
sunsmile2015 2:2d9d4b271af8 78 ble(_ble),
sunsmile2015 2:2d9d4b271af8 79 valueBytes(hrmCounter),
sunsmile2015 2:2d9d4b271af8 80 hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
sunsmile2015 2:2d9d4b271af8 81 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
sunsmile2015 2:2d9d4b271af8 82 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
sunsmile2015 2:2d9d4b271af8 83 hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
sunsmile2015 2:2d9d4b271af8 84 controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
sunsmile2015 2:2d9d4b271af8 85 setupService();
sunsmile2015 2:2d9d4b271af8 86 }
sunsmile2015 2:2d9d4b271af8 87
sunsmile2015 2:2d9d4b271af8 88 /**
sunsmile2015 2:2d9d4b271af8 89 * @brief Set a new 8-bit value for heart rate.
sunsmile2015 2:2d9d4b271af8 90 *
sunsmile2015 2:2d9d4b271af8 91 * @param[in] hrmCounter
sunsmile2015 2:2d9d4b271af8 92 * HeartRate in bpm.
sunsmile2015 2:2d9d4b271af8 93 */
sunsmile2015 2:2d9d4b271af8 94 void updateHeartRate(uint8_t hrmCounter) {
sunsmile2015 2:2d9d4b271af8 95 valueBytes.updateHeartRate(hrmCounter);
sunsmile2015 2:2d9d4b271af8 96 ble.updateCharacteristicValue(hrmRate.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
sunsmile2015 2:2d9d4b271af8 97 }
sunsmile2015 2:2d9d4b271af8 98
sunsmile2015 2:2d9d4b271af8 99 /**
sunsmile2015 2:2d9d4b271af8 100 * Set a new 16-bit value for heart rate.
sunsmile2015 2:2d9d4b271af8 101 *
sunsmile2015 2:2d9d4b271af8 102 * @param[in] hrmCounter
sunsmile2015 2:2d9d4b271af8 103 * HeartRate in bpm.
sunsmile2015 2:2d9d4b271af8 104 */
sunsmile2015 2:2d9d4b271af8 105 void updateHeartRate(uint16_t hrmCounter) {
sunsmile2015 2:2d9d4b271af8 106 valueBytes.updateHeartRate(hrmCounter);
sunsmile2015 2:2d9d4b271af8 107 ble.updateCharacteristicValue(hrmRate.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
sunsmile2015 2:2d9d4b271af8 108 }
sunsmile2015 2:2d9d4b271af8 109
sunsmile2015 2:2d9d4b271af8 110 /**
sunsmile2015 2:2d9d4b271af8 111 * This callback allows the HeartRateSecService to receive updates to the
sunsmile2015 2:2d9d4b271af8 112 * controlPoint Characteristic.
sunsmile2015 2:2d9d4b271af8 113 *
sunsmile2015 2:2d9d4b271af8 114 * @param[in] params
sunsmile2015 2:2d9d4b271af8 115 * Information about the characterisitc being updated.
sunsmile2015 2:2d9d4b271af8 116 */
sunsmile2015 2:2d9d4b271af8 117 virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) {
sunsmile2015 2:2d9d4b271af8 118 if (params->charHandle == controlPoint.getValueAttribute().getHandle()) {
sunsmile2015 2:2d9d4b271af8 119 /* Do something here if the new value is 1; else you can override this method by
sunsmile2015 2:2d9d4b271af8 120 * extending this class.
sunsmile2015 2:2d9d4b271af8 121 * @NOTE: if you are extending this class, be sure to also call
sunsmile2015 2:2d9d4b271af8 122 * ble.onDataWritten(this, &ExtendedHRService::onDataWritten); in
sunsmile2015 2:2d9d4b271af8 123 * your constructor.
sunsmile2015 2:2d9d4b271af8 124 */
sunsmile2015 2:2d9d4b271af8 125 }
sunsmile2015 2:2d9d4b271af8 126 }
sunsmile2015 2:2d9d4b271af8 127
sunsmile2015 2:2d9d4b271af8 128 private:
sunsmile2015 2:2d9d4b271af8 129 void setupService(void) {
sunsmile2015 2:2d9d4b271af8 130 static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
sunsmile2015 2:2d9d4b271af8 131 if (serviceAdded) {
sunsmile2015 2:2d9d4b271af8 132 return;
sunsmile2015 2:2d9d4b271af8 133 }
sunsmile2015 2:2d9d4b271af8 134
sunsmile2015 2:2d9d4b271af8 135 hrmRate.requireSecurity( Gap::SECURITY_MODE_ENCRYPTION_WITH_MITM);
sunsmile2015 2:2d9d4b271af8 136 GattCharacteristic *charTable[] = {&hrmRate, &hrmLocation, &controlPoint};
sunsmile2015 2:2d9d4b271af8 137 GattService hrmService(GattService::UUID_HEART_RATE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
sunsmile2015 2:2d9d4b271af8 138
sunsmile2015 2:2d9d4b271af8 139 ble.addService(hrmService);
sunsmile2015 2:2d9d4b271af8 140 serviceAdded = true;
sunsmile2015 2:2d9d4b271af8 141
sunsmile2015 2:2d9d4b271af8 142 ble.onDataWritten(this, &HeartRateSecService::onDataWritten);
sunsmile2015 2:2d9d4b271af8 143 }
sunsmile2015 2:2d9d4b271af8 144
sunsmile2015 2:2d9d4b271af8 145 private:
sunsmile2015 2:2d9d4b271af8 146 /* Private internal representation for the bytes used to work with the vaulue of the heart-rate characteristic. */
sunsmile2015 2:2d9d4b271af8 147 struct HeartRateValueBytes {
sunsmile2015 2:2d9d4b271af8 148 static const unsigned MAX_VALUE_BYTES = 3; /* FLAGS + up to two bytes for heart-rate */
sunsmile2015 2:2d9d4b271af8 149 static const unsigned FLAGS_BYTE_INDEX = 0;
sunsmile2015 2:2d9d4b271af8 150
sunsmile2015 2:2d9d4b271af8 151 static const unsigned VALUE_FORMAT_BITNUM = 0;
sunsmile2015 2:2d9d4b271af8 152 static const uint8_t VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM);
sunsmile2015 2:2d9d4b271af8 153
sunsmile2015 2:2d9d4b271af8 154 HeartRateValueBytes(uint8_t hrmCounter) : valueBytes() {
sunsmile2015 2:2d9d4b271af8 155 updateHeartRate(hrmCounter);
sunsmile2015 2:2d9d4b271af8 156 }
sunsmile2015 2:2d9d4b271af8 157
sunsmile2015 2:2d9d4b271af8 158 HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() {
sunsmile2015 2:2d9d4b271af8 159 updateHeartRate(hrmCounter);
sunsmile2015 2:2d9d4b271af8 160 }
sunsmile2015 2:2d9d4b271af8 161
sunsmile2015 2:2d9d4b271af8 162 void updateHeartRate(uint8_t hrmCounter) {
sunsmile2015 2:2d9d4b271af8 163 valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG;
sunsmile2015 2:2d9d4b271af8 164 valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter;
sunsmile2015 2:2d9d4b271af8 165 }
sunsmile2015 2:2d9d4b271af8 166
sunsmile2015 2:2d9d4b271af8 167 void updateHeartRate(uint16_t hrmCounter) {
sunsmile2015 2:2d9d4b271af8 168 valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG;
sunsmile2015 2:2d9d4b271af8 169 valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF);
sunsmile2015 2:2d9d4b271af8 170 valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8);
sunsmile2015 2:2d9d4b271af8 171 }
sunsmile2015 2:2d9d4b271af8 172
sunsmile2015 2:2d9d4b271af8 173 uint8_t *getPointer(void) {
sunsmile2015 2:2d9d4b271af8 174 return valueBytes;
sunsmile2015 2:2d9d4b271af8 175 }
sunsmile2015 2:2d9d4b271af8 176
sunsmile2015 2:2d9d4b271af8 177 const uint8_t *getPointer(void) const {
sunsmile2015 2:2d9d4b271af8 178 return valueBytes;
sunsmile2015 2:2d9d4b271af8 179 }
sunsmile2015 2:2d9d4b271af8 180
sunsmile2015 2:2d9d4b271af8 181 unsigned getNumValueBytes(void) const {
sunsmile2015 2:2d9d4b271af8 182 return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) ? sizeof(uint16_t) : sizeof(uint8_t));
sunsmile2015 2:2d9d4b271af8 183 }
sunsmile2015 2:2d9d4b271af8 184
sunsmile2015 2:2d9d4b271af8 185 private:
sunsmile2015 2:2d9d4b271af8 186 /* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */
sunsmile2015 2:2d9d4b271af8 187 /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */
sunsmile2015 2:2d9d4b271af8 188 uint8_t valueBytes[MAX_VALUE_BYTES];
sunsmile2015 2:2d9d4b271af8 189 };
sunsmile2015 2:2d9d4b271af8 190
sunsmile2015 2:2d9d4b271af8 191 private:
sunsmile2015 2:2d9d4b271af8 192 BLEDevice &ble;
sunsmile2015 2:2d9d4b271af8 193
sunsmile2015 2:2d9d4b271af8 194 HeartRateValueBytes valueBytes;
sunsmile2015 2:2d9d4b271af8 195 uint8_t controlPointValue;
sunsmile2015 2:2d9d4b271af8 196
sunsmile2015 2:2d9d4b271af8 197 GattCharacteristic hrmRate;
sunsmile2015 2:2d9d4b271af8 198 ReadOnlyGattCharacteristic<uint8_t> hrmLocation;
sunsmile2015 2:2d9d4b271af8 199 WriteOnlyGattCharacteristic<uint8_t> controlPoint;
sunsmile2015 2:2d9d4b271af8 200 };
sunsmile2015 2:2d9d4b271af8 201
sunsmile2015 2:2d9d4b271af8 202 #endif /* #ifndef __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__*/