Heart Rate Monitor with security API for Delta BLE platform

Fork of BLE_HeartRate_DELTA by Delta

Committer:
silviaChen
Date:
Tue Mar 28 08:21:46 2017 +0000
Revision:
2:0737743120d7
Add BLE bonding/pairing function

Who changed what in which revision?

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