Rizky Ardi Maulana / mbed-os
Committer:
elessair
Date:
Sun Oct 23 15:10:02 2016 +0000
Revision:
0:f269e3021894
Initial commit

Who changed what in which revision?

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