Fork of BLE_SecureHeartRate : should this 'work' i.e. require a secure connection on an nRF51-DK? Hopefully I'm just missing something obvious - or is this broken?

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_SecureHeartRate by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HeartRateSecService.h Source File

HeartRateSecService.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__
00018 #define __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__
00019 
00020 #include "BLE.h"
00021 
00022 /**
00023 * @class HeartRateSecService
00024 * @brief BLE Service for HeartRate. This BLE Service contains the location of the sensor, the heartrate in beats per minute. <br>
00025 * Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml <br>
00026 * HRM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml <br>
00027 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml
00028 */
00029 class HeartRateSecService {
00030 public:
00031     /**
00032     * @enum SensorLocation
00033     * @brief Location of HeartRate sensor on body.
00034     */
00035     enum {
00036         LOCATION_OTHER  = 0, /*!< Other Location */
00037         LOCATION_CHEST ,     /*!< Chest */
00038         LOCATION_WRIST ,     /*!< Wrist */
00039         LOCATION_FINGER ,    /*!< Finger */
00040         LOCATION_HAND ,      /*!< Hand */
00041         LOCATION_EAR_LOBE ,  /*!< Earlobe */
00042         LOCATION_FOOT ,      /*!< Foot */
00043     };
00044 
00045 public:
00046     /**
00047      * @brief Constructor with 8bit HRM Counter value.
00048      *
00049      * @param[ref] _ble
00050      *               Reference to the underlying BLEDevice.
00051      * @param[in] hrmCounter (8-bit)
00052      *               initial value for the hrm counter.
00053      * @param[in] location
00054      *               Sensor's location.
00055      */
00056     HeartRateSecService(BLE &_ble, uint8_t hrmCounter, uint8_t location) :
00057         ble(_ble),
00058         valueBytes(hrmCounter),
00059         hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
00060                 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
00061                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
00062         hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
00063         controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
00064         setupService();
00065     }
00066 
00067     /**
00068      * @brief Constructor with a 16-bit HRM Counter value.
00069      *
00070      * @param[in] _ble
00071      *               Reference to the underlying BLEDevice.
00072      * @param[in] hrmCounter (8-bit)
00073      *               initial value for the hrm counter.
00074      * @param[in] location
00075      *               Sensor's location.
00076      */
00077     HeartRateSecService(BLE &_ble, uint16_t hrmCounter, uint8_t location) :
00078         ble(_ble),
00079         valueBytes(hrmCounter),
00080         hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(),
00081                 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES,
00082                 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
00083         hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location),
00084         controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) {
00085         setupService();
00086     }
00087     
00088     /*void setSecurityStatus(Gap::Handle_t handle) {
00089         SecurityManager::LinkSecurityStatus_t status;
00090         ble_error_t ret = ble.securityManager().setLinkSecurity(handle, &status);
00091         if (BLE_ERROR_NONE == ret) {
00092             printf("OK: getLinkSecurity status: ");
00093             switch (status) {
00094                 case SecurityManager::NOT_ENCRYPTED:          // The link is not secured.
00095                     printf("NOT_ENCRYPTED");
00096                     break;
00097                 case SecurityManager::ENCRYPTION_IN_PROGRESS: // Link security is being established
00098                     printf("ENCRYPTION_IN_PROGRESS");
00099                     break;
00100                 case SecurityManager::ENCRYPTED:
00101                     printf("ENCRYPTED");
00102                     break;
00103             }
00104             printf("\r\n");
00105         } else {
00106             printf("FAIL: getLinkSecurity ret %i\r\n", ret);
00107         }
00108     }*/
00109     
00110     void outputSecurityStatus (Gap::Handle_t handle) {
00111         SecurityManager::LinkSecurityStatus_t status;
00112         ble_error_t ret = ble.securityManager().getLinkSecurity(handle, &status);
00113         if (BLE_ERROR_NONE == ret) {
00114             printf("OK: getLinkSecurity status: ");
00115             switch (status) {
00116                 case SecurityManager::NOT_ENCRYPTED:          /**< The link is not secured. */
00117                     printf("NOT_ENCRYPTED");
00118                     break;
00119                 case SecurityManager::ENCRYPTION_IN_PROGRESS: /**< Link security is being established.*/
00120                     printf("ENCRYPTION_IN_PROGRESS");
00121                     break;
00122                 case SecurityManager::ENCRYPTED:
00123                     printf("ENCRYPTED");
00124                     break;
00125             }
00126             printf("\r\n");
00127         } else {
00128             printf("FAIL: getLinkSecurity ret %i\r\n", ret);
00129         }
00130     }
00131 
00132     /**
00133      * @brief Set a new 8-bit value for heart rate.
00134      *
00135      * @param[in] hrmCounter
00136      *                  HeartRate in bpm.
00137      */
00138     void updateHeartRate(uint8_t hrmCounter) {
00139         valueBytes.updateHeartRate(hrmCounter);
00140         ble.gattServer().write(hrmRate.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
00141     }
00142 
00143     /**
00144      * Set a new 16-bit value for heart rate.
00145      *
00146      * @param[in] hrmCounter
00147      *                  HeartRate in bpm.
00148      */
00149     void updateHeartRate(uint16_t hrmCounter) {
00150         valueBytes.updateHeartRate(hrmCounter);
00151         ble.gattServer().write(hrmRate.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
00152     }
00153 
00154     /**
00155      * This callback allows the HeartRateSecService to receive updates to the
00156      * controlPoint Characteristic.
00157      *
00158      * @param[in] params
00159      *     Information about the characterisitc being updated.
00160      */
00161     virtual void onDataWritten(const GattWriteCallbackParams *params) {
00162         if (params->handle == controlPoint.getValueAttribute().getHandle()) {
00163             /* Do something here if the new value is 1; else you can override this method by
00164              * extending this class.
00165              * @NOTE: if you are extending this class, be sure to also call
00166              * ble.onDataWritten(this, &ExtendedHRService::onDataWritten); in
00167              * your constructor.
00168              */
00169         }
00170     }
00171 
00172 private:
00173     void setupService(void) {
00174         static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
00175         if (serviceAdded) {
00176             return;
00177         }
00178         
00179         hrmRate.requireSecurity(SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM);
00180 
00181         GattCharacteristic *charTable[] = {&hrmRate, &hrmLocation, &controlPoint};
00182         GattService         hrmService(GattService::UUID_HEART_RATE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
00183 
00184         ble.gattServer().addService(hrmService);
00185         serviceAdded = true;
00186 
00187         ble.gattServer().onDataWritten(this, &HeartRateSecService::onDataWritten);
00188     }
00189 
00190 private:
00191     /* Private internal representation for the bytes used to work with the vaulue of the heart-rate characteristic. */
00192     struct HeartRateValueBytes {
00193         static const unsigned MAX_VALUE_BYTES  = 3; /* FLAGS + up to two bytes for heart-rate */
00194         static const unsigned FLAGS_BYTE_INDEX = 0;
00195 
00196         static const unsigned VALUE_FORMAT_BITNUM = 0;
00197         static const uint8_t  VALUE_FORMAT_FLAG   = (1 << VALUE_FORMAT_BITNUM);
00198 
00199         HeartRateValueBytes(uint8_t hrmCounter) : valueBytes() {
00200             updateHeartRate(hrmCounter);
00201         }
00202 
00203         HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() {
00204             updateHeartRate(hrmCounter);
00205         }
00206 
00207         void updateHeartRate(uint8_t hrmCounter) {
00208             valueBytes[FLAGS_BYTE_INDEX]    &= ~VALUE_FORMAT_FLAG;
00209             valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter;
00210         }
00211 
00212         void updateHeartRate(uint16_t hrmCounter) {
00213             valueBytes[FLAGS_BYTE_INDEX]    |= VALUE_FORMAT_FLAG;
00214             valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF);
00215             valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8);
00216         }
00217 
00218         uint8_t       *getPointer(void) {
00219             return valueBytes;
00220         }
00221 
00222         const uint8_t *getPointer(void) const {
00223             return valueBytes;
00224         }
00225 
00226         unsigned       getNumValueBytes(void) const {
00227             return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) ? sizeof(uint16_t) : sizeof(uint8_t));
00228         }
00229 
00230 private:
00231         /* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */
00232         /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */
00233         uint8_t valueBytes[MAX_VALUE_BYTES];
00234     };
00235 
00236 private:
00237     BLE                 &ble;
00238 
00239     HeartRateValueBytes  valueBytes;
00240     uint8_t              controlPointValue;
00241 
00242     GattCharacteristic                   hrmRate;
00243     ReadOnlyGattCharacteristic<uint8_t>  hrmLocation;
00244     WriteOnlyGattCharacteristic<uint8_t> controlPoint;
00245 };
00246 
00247 #endif /* #ifndef __BLE_HEART_RATE_SEC_SAMPLE_SERVICE_H__*/