Graduation Thesis, use Nucleo and X-Nucleo BLE

Dependencies:   PulseSensor GSM Thermometer KalmanFilter

Committer:
DuyLionTran
Date:
Wed May 23 17:33:11 2018 +0000
Revision:
16:0325e647496f
Parent:
15:00a1c0ea570c
Child:
17:b7c2db3e7282
HTS Type and HRM Location can be changed by use through BLE

Who changed what in which revision?

UserRevisionLine numberNew contents of line
DuyLionTran 0:64ca984b3efd 1 #ifndef __BLE_HEALTHCARE_SERVICE_H__
DuyLionTran 0:64ca984b3efd 2 #define __BLE_HEALTHCARE_SERVICE_H__
DuyLionTran 0:64ca984b3efd 3
DuyLionTran 0:64ca984b3efd 4 #include "ble/BLE.h"
DuyLionTran 0:64ca984b3efd 5
DuyLionTran 0:64ca984b3efd 6 /**
DuyLionTran 0:64ca984b3efd 7 * @class HealthCareService
DuyLionTran 0:64ca984b3efd 8 * @brief
DuyLionTran 0:64ca984b3efd 9 */
DuyLionTran 0:64ca984b3efd 10 class HealthCareService {
DuyLionTran 0:64ca984b3efd 11 public:
DuyLionTran 0:64ca984b3efd 12 /**
DuyLionTran 0:64ca984b3efd 13 * @brief Location of sensor on the body.
DuyLionTran 0:64ca984b3efd 14 */
DuyLionTran 0:64ca984b3efd 15 enum TemperatureSensorLocation_t {
DuyLionTran 0:64ca984b3efd 16 TEMPERATURE_LOCATION_ARMPIT = 1, /*!< Armpit. */
DuyLionTran 0:64ca984b3efd 17 TEMPERATURE_LOCATION_BODY, /*!< Body. */
DuyLionTran 0:64ca984b3efd 18 TEMPERATURE_LOCATION_EAR, /*!< Ear. */
DuyLionTran 0:64ca984b3efd 19 TEMPERATURE_LOCATION_FINGER, /*!< Finger. */
DuyLionTran 0:64ca984b3efd 20 TEMPERATURE_LOCATION_GI_TRACT, /*!< GI tract */
DuyLionTran 0:64ca984b3efd 21 TEMPERATURE_LOCATION_MOUTH, /*!< Mouth. */
DuyLionTran 0:64ca984b3efd 22 TEMPERATURE_LOCATION_RECTUM, /*!< Rectum. */
DuyLionTran 0:64ca984b3efd 23 TEMPERATURE_LOCATION_TOE, /*!< Toe. */
DuyLionTran 0:64ca984b3efd 24 TEMPERATURE_LOCATION_EAR_DRUM, /*!< Eardrum. */
DuyLionTran 0:64ca984b3efd 25 };
DuyLionTran 0:64ca984b3efd 26 /**
DuyLionTran 0:64ca984b3efd 27 * Intended location of the heart rate sensor.
DuyLionTran 0:64ca984b3efd 28 */
DuyLionTran 0:64ca984b3efd 29 enum HeartRateSensorLocation_t {
DuyLionTran 0:64ca984b3efd 30 HRM_LOCATION_OTHER = 0, /*!< Other lacation. */
DuyLionTran 0:64ca984b3efd 31 HRM_LOCATION_CHEST = 1, /*!< Chest. */
DuyLionTran 0:64ca984b3efd 32 HRM_LOCATION_WRIST = 2, /*!< Wrist. */
DuyLionTran 0:64ca984b3efd 33 HRM_LOCATION_FINGER, /*!< Finger. */
DuyLionTran 0:64ca984b3efd 34 HRM_LOCATION_HAND, /*!< Hand. */
DuyLionTran 0:64ca984b3efd 35 HRM_LOCATION_EAR_LOBE, /*!< Ear lob. */
DuyLionTran 0:64ca984b3efd 36 HRM_LOCATION_FOOT, /*!< Foot. */
DuyLionTran 8:3384286a8498 37 };
DuyLionTran 8:3384286a8498 38
DuyLionTran 9:be09a9bf2e2e 39 const static uint16_t DEVICE_INFO_SERVICE_UUID = 0x180A;
DuyLionTran 8:3384286a8498 40 const static uint16_t USER_DATA_SERVICE_UUID = 0x181C;
DuyLionTran 8:3384286a8498 41 const static uint16_t USER_DATA_DIGITAL_CHARACTERISTIC_UUID = 0x2A57;
DuyLionTran 0:64ca984b3efd 42
DuyLionTran 0:64ca984b3efd 43 public:
DuyLionTran 0:64ca984b3efd 44 /**
DuyLionTran 0:64ca984b3efd 45 * @param[in] _ble Reference to the BLE device.
DuyLionTran 0:64ca984b3efd 46 * @param[in] initialTemp Initial value in celsius.
DuyLionTran 0:64ca984b3efd 47 * @param[in] _tempLocation Location of the thermometer.
DuyLionTran 0:64ca984b3efd 48 * @param[in] hrmCounter Heart beats per minute measured by the heart rate sensor.
DuyLionTran 0:64ca984b3efd 49 * @param[in] _HRMlocation Intended location of the heart rate sensor.
DuyLionTran 8:3384286a8498 50 * @param[in] controlVal_1 Optional control value 1
DuyLionTran 0:64ca984b3efd 51 */
DuyLionTran 0:64ca984b3efd 52 HealthCareService(BLE &_ble,
DuyLionTran 0:64ca984b3efd 53 float initialTemp,
DuyLionTran 0:64ca984b3efd 54 uint8_t _tempLocation,
DuyLionTran 0:64ca984b3efd 55 // ) :
DuyLionTran 1:9eadd2dc4b6e 56 uint8_t hrmCounter,
DuyLionTran 8:3384286a8498 57 uint8_t _hrmLocation,
DuyLionTran 8:3384286a8498 58 uint8_t controlVal_1
DuyLionTran 8:3384286a8498 59 ) :
DuyLionTran 0:64ca984b3efd 60 ble(_ble),
DuyLionTran 0:64ca984b3efd 61 temperatureValueByte(initialTemp),
DuyLionTran 1:9eadd2dc4b6e 62 hrmValueByte(hrmCounter),
DuyLionTran 2:16f6cfcd7505 63 tempMeasurement(
DuyLionTran 2:16f6cfcd7505 64 GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR,
DuyLionTran 2:16f6cfcd7505 65 (TemperatureValueBytes *)temperatureValueByte.getPointer(),
DuyLionTran 2:16f6cfcd7505 66 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
DuyLionTran 2:16f6cfcd7505 67 tempLocation(
DuyLionTran 2:16f6cfcd7505 68 GattCharacteristic::UUID_TEMPERATURE_TYPE_CHAR,
DuyLionTran 2:16f6cfcd7505 69 &_tempLocation),
DuyLionTran 2:16f6cfcd7505 70 hrmRate(
DuyLionTran 2:16f6cfcd7505 71 GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR,
DuyLionTran 2:16f6cfcd7505 72 hrmValueByte.getPointer(),
DuyLionTran 2:16f6cfcd7505 73 hrmValueByte.getNumValueBytes(),
DuyLionTran 2:16f6cfcd7505 74 HeartRateValueBytes::MAX_VALUE_BYTES,
DuyLionTran 2:16f6cfcd7505 75 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
DuyLionTran 0:64ca984b3efd 76 hrmLocation(
DuyLionTran 0:64ca984b3efd 77 GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR,
DuyLionTran 8:3384286a8498 78 reinterpret_cast<uint8_t*>(&_hrmLocation)),
DuyLionTran 8:3384286a8498 79 controlState(USER_DATA_DIGITAL_CHARACTERISTIC_UUID,
DuyLionTran 11:5a4313edf10d 80 &controlVal_1)
DuyLionTran 11:5a4313edf10d 81 /* UUID_GLUCOSE_SERVICE UUID_HEALTH_THERMOMETER_SERVICE */
DuyLionTran 0:64ca984b3efd 82
DuyLionTran 0:64ca984b3efd 83 {
DuyLionTran 2:16f6cfcd7505 84 GattCharacteristic *HealthThermChars[] = {&tempMeasurement, &tempLocation};
DuyLionTran 11:5a4313edf10d 85 GattService HealthThermService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, HealthThermChars, sizeof(HealthThermChars) / sizeof(GattCharacteristic *));
DuyLionTran 2:16f6cfcd7505 86 ble.addService(HealthThermService);
DuyLionTran 2:16f6cfcd7505 87
DuyLionTran 8:3384286a8498 88 GattCharacteristic *HRMChars[] = {&hrmRate, &hrmLocation};
DuyLionTran 2:16f6cfcd7505 89 GattService HRMService(GattService::UUID_HEART_RATE_SERVICE , HRMChars, sizeof(HRMChars) / sizeof(GattCharacteristic *));
DuyLionTran 2:16f6cfcd7505 90 ble.addService(HRMService);
DuyLionTran 8:3384286a8498 91
DuyLionTran 8:3384286a8498 92 GattCharacteristic *CONChars[] = {&controlState};
DuyLionTran 8:3384286a8498 93 GattService CONService(USER_DATA_SERVICE_UUID , CONChars, sizeof(CONChars) / sizeof(GattCharacteristic *));
DuyLionTran 8:3384286a8498 94 ble.addService(CONService);
DuyLionTran 0:64ca984b3efd 95 }
DuyLionTran 0:64ca984b3efd 96
DuyLionTran 8:3384286a8498 97 GattAttribute::Handle_t getValueHandle() const
DuyLionTran 8:3384286a8498 98 {
DuyLionTran 8:3384286a8498 99 return controlState.getValueHandle();
DuyLionTran 8:3384286a8498 100 }
DuyLionTran 8:3384286a8498 101
DuyLionTran 16:0325e647496f 102 GattAttribute::Handle_t getTypeHandle() const
DuyLionTran 16:0325e647496f 103 {
DuyLionTran 16:0325e647496f 104 return tempLocation.getValueHandle();
DuyLionTran 16:0325e647496f 105 }
DuyLionTran 16:0325e647496f 106
DuyLionTran 16:0325e647496f 107 GattAttribute::Handle_t getLocationHandle() const
DuyLionTran 16:0325e647496f 108 {
DuyLionTran 16:0325e647496f 109 return hrmLocation.getValueHandle();
DuyLionTran 16:0325e647496f 110 }
DuyLionTran 16:0325e647496f 111
DuyLionTran 0:64ca984b3efd 112 /**
DuyLionTran 0:64ca984b3efd 113 * @brief Update the temperature being broadcast.
DuyLionTran 0:64ca984b3efd 114 * @param[in] temperature Floating point value of the temperature.
DuyLionTran 0:64ca984b3efd 115 */
DuyLionTran 0:64ca984b3efd 116 void updateTemperature(float temperature) {
DuyLionTran 0:64ca984b3efd 117 if (ble.getGapState().connected) {
DuyLionTran 0:64ca984b3efd 118 temperatureValueByte.updateTemperature(temperature);
DuyLionTran 0:64ca984b3efd 119 ble.gattServer().write(tempMeasurement.getValueHandle(), temperatureValueByte.getPointer(), sizeof(TemperatureValueBytes));
DuyLionTran 0:64ca984b3efd 120 }
DuyLionTran 0:64ca984b3efd 121 }
DuyLionTran 0:64ca984b3efd 122
DuyLionTran 0:64ca984b3efd 123 /**
DuyLionTran 14:e6029b780879 124 * @brief Update the temperature location.
DuyLionTran 0:64ca984b3efd 125 * @param loc New location value.
DuyLionTran 0:64ca984b3efd 126 */
DuyLionTran 16:0325e647496f 127 void updateType(uint8_t loc) {
DuyLionTran 0:64ca984b3efd 128 ble.gattServer().write(tempLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t));
DuyLionTran 0:64ca984b3efd 129 }
DuyLionTran 0:64ca984b3efd 130
DuyLionTran 0:64ca984b3efd 131 /**
DuyLionTran 16:0325e647496f 132 * @brief Update the temperature location.
DuyLionTran 16:0325e647496f 133 * @param loc New location value.
DuyLionTran 16:0325e647496f 134 */
DuyLionTran 16:0325e647496f 135 void updateLocation(uint8_t loc) {
DuyLionTran 16:0325e647496f 136 ble.gattServer().write(hrmLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t));
DuyLionTran 16:0325e647496f 137 }
DuyLionTran 16:0325e647496f 138
DuyLionTran 16:0325e647496f 139 /**
DuyLionTran 0:64ca984b3efd 140 * Update the heart rate that the service exposes.
DuyLionTran 0:64ca984b3efd 141 * The server sends a notification of the new value to clients that have
DuyLionTran 0:64ca984b3efd 142 * subscribed to updates of the heart rate measurement characteristic; clients
DuyLionTran 0:64ca984b3efd 143 * reading the heart rate measurement characteristic after the update obtain
DuyLionTran 0:64ca984b3efd 144 * the updated value.
DuyLionTran 0:64ca984b3efd 145 *
DuyLionTran 0:64ca984b3efd 146 * @param[in] hrmCounter Heart rate measured in BPM.
DuyLionTran 0:64ca984b3efd 147 * @attention This function must be called in the execution context of the BLE stack.
DuyLionTran 0:64ca984b3efd 148 */
DuyLionTran 0:64ca984b3efd 149 void updateHeartRate(uint16_t hrmCounter) {
DuyLionTran 1:9eadd2dc4b6e 150 hrmValueByte.updateHeartRate(hrmCounter);
DuyLionTran 1:9eadd2dc4b6e 151 ble.gattServer().write(
DuyLionTran 1:9eadd2dc4b6e 152 hrmRate.getValueHandle(),
DuyLionTran 1:9eadd2dc4b6e 153 hrmValueByte.getPointer(),
DuyLionTran 1:9eadd2dc4b6e 154 hrmValueByte.getNumValueBytes()
DuyLionTran 1:9eadd2dc4b6e 155 );
DuyLionTran 0:64ca984b3efd 156 }
DuyLionTran 0:64ca984b3efd 157
DuyLionTran 0:64ca984b3efd 158 private:
DuyLionTran 0:64ca984b3efd 159 /* Private internal representation for the bytes used to work with the vaulue of the temperature characteristic. */
DuyLionTran 0:64ca984b3efd 160 struct TemperatureValueBytes {
DuyLionTran 0:64ca984b3efd 161 static const unsigned OFFSET_OF_FLAGS = 0;
DuyLionTran 0:64ca984b3efd 162 static const unsigned OFFSET_OF_VALUE = OFFSET_OF_FLAGS + sizeof(uint8_t);
DuyLionTran 0:64ca984b3efd 163 static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float);
DuyLionTran 0:64ca984b3efd 164
DuyLionTran 0:64ca984b3efd 165 static const unsigned TEMPERATURE_UNITS_FLAG_POS = 0;
DuyLionTran 0:64ca984b3efd 166 static const unsigned TIMESTAMP_FLAG_POS = 1;
DuyLionTran 0:64ca984b3efd 167 static const unsigned TEMPERATURE_TYPE_FLAG_POS = 2;
DuyLionTran 0:64ca984b3efd 168
DuyLionTran 0:64ca984b3efd 169 static const uint8_t TEMPERATURE_UNITS_CELSIUS = 0;
DuyLionTran 0:64ca984b3efd 170 static const uint8_t TEMPERATURE_UNITS_FAHRENHEIT = 1;
DuyLionTran 0:64ca984b3efd 171
DuyLionTran 0:64ca984b3efd 172 TemperatureValueBytes(float initialTemperature) : bytes() {
DuyLionTran 0:64ca984b3efd 173 /* Assumption: temperature values are expressed in celsius */
DuyLionTran 0:64ca984b3efd 174 bytes[OFFSET_OF_FLAGS] = (TEMPERATURE_UNITS_CELSIUS << TEMPERATURE_UNITS_FLAG_POS) |
DuyLionTran 0:64ca984b3efd 175 (false << TIMESTAMP_FLAG_POS) |
DuyLionTran 0:64ca984b3efd 176 (false << TEMPERATURE_TYPE_FLAG_POS);
DuyLionTran 0:64ca984b3efd 177 updateTemperature(initialTemperature);
DuyLionTran 0:64ca984b3efd 178 }
DuyLionTran 0:64ca984b3efd 179
DuyLionTran 0:64ca984b3efd 180 void updateTemperature(float temp) {
DuyLionTran 0:64ca984b3efd 181 uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp);
DuyLionTran 0:64ca984b3efd 182 memcpy(&bytes[OFFSET_OF_VALUE], &temp_ieee11073, sizeof(float));
DuyLionTran 0:64ca984b3efd 183 }
DuyLionTran 0:64ca984b3efd 184
DuyLionTran 0:64ca984b3efd 185 uint8_t *getPointer(void) {
DuyLionTran 0:64ca984b3efd 186 return bytes;
DuyLionTran 0:64ca984b3efd 187 }
DuyLionTran 0:64ca984b3efd 188
DuyLionTran 0:64ca984b3efd 189 const uint8_t *getPointer(void) const {
DuyLionTran 0:64ca984b3efd 190 return bytes;
DuyLionTran 0:64ca984b3efd 191 }
DuyLionTran 0:64ca984b3efd 192
DuyLionTran 0:64ca984b3efd 193 private:
DuyLionTran 0:64ca984b3efd 194 /**
DuyLionTran 0:64ca984b3efd 195 * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type.
DuyLionTran 0:64ca984b3efd 196 * @param temperature The temperature as a float.
DuyLionTran 0:64ca984b3efd 197 * @return The temperature in 11073-20601 FLOAT-Type format.
DuyLionTran 0:64ca984b3efd 198 */
DuyLionTran 0:64ca984b3efd 199 uint32_t quick_ieee11073_from_float(float temperature) {
DuyLionTran 0:64ca984b3efd 200 uint8_t exponent = 0xFE; //Exponent is -2
DuyLionTran 0:64ca984b3efd 201 uint32_t mantissa = (uint32_t)(temperature * 100);
DuyLionTran 0:64ca984b3efd 202
DuyLionTran 0:64ca984b3efd 203 return (((uint32_t)exponent) << 24) | mantissa;
DuyLionTran 0:64ca984b3efd 204 }
DuyLionTran 0:64ca984b3efd 205
DuyLionTran 0:64ca984b3efd 206 private:
DuyLionTran 0:64ca984b3efd 207 /* First byte: 8-bit flags. Second field is a float holding the temperature value. */
DuyLionTran 0:64ca984b3efd 208 /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
DuyLionTran 0:64ca984b3efd 209 uint8_t bytes[SIZEOF_VALUE_BYTES];
DuyLionTran 0:64ca984b3efd 210 };
DuyLionTran 0:64ca984b3efd 211
DuyLionTran 0:64ca984b3efd 212 protected:
DuyLionTran 0:64ca984b3efd 213 /*
DuyLionTran 0:64ca984b3efd 214 * Heart rate measurement value.
DuyLionTran 0:64ca984b3efd 215 */
DuyLionTran 0:64ca984b3efd 216 struct HeartRateValueBytes {
DuyLionTran 0:64ca984b3efd 217 /* 1 byte for the Flags, and up to two bytes for heart rate value. */
DuyLionTran 0:64ca984b3efd 218 static const unsigned MAX_VALUE_BYTES = 3;
DuyLionTran 0:64ca984b3efd 219 static const unsigned FLAGS_BYTE_INDEX = 0;
DuyLionTran 0:64ca984b3efd 220
DuyLionTran 0:64ca984b3efd 221 static const unsigned VALUE_FORMAT_BITNUM = 0;
DuyLionTran 0:64ca984b3efd 222 static const uint8_t VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM);
DuyLionTran 0:64ca984b3efd 223
DuyLionTran 0:64ca984b3efd 224 HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() {
DuyLionTran 0:64ca984b3efd 225 updateHeartRate(hrmCounter);
DuyLionTran 0:64ca984b3efd 226 }
DuyLionTran 0:64ca984b3efd 227
DuyLionTran 0:64ca984b3efd 228 void updateHeartRate(uint16_t hrmCounter) {
DuyLionTran 0:64ca984b3efd 229 if (hrmCounter <= 255) {
DuyLionTran 0:64ca984b3efd 230 valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG;
DuyLionTran 0:64ca984b3efd 231 valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter;
DuyLionTran 0:64ca984b3efd 232 } else {
DuyLionTran 0:64ca984b3efd 233 valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG;
DuyLionTran 0:64ca984b3efd 234 valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF);
DuyLionTran 0:64ca984b3efd 235 valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8);
DuyLionTran 0:64ca984b3efd 236 }
DuyLionTran 0:64ca984b3efd 237 }
DuyLionTran 0:64ca984b3efd 238
DuyLionTran 0:64ca984b3efd 239 uint8_t *getPointer(void) {
DuyLionTran 0:64ca984b3efd 240 return valueBytes;
DuyLionTran 0:64ca984b3efd 241 }
DuyLionTran 0:64ca984b3efd 242
DuyLionTran 0:64ca984b3efd 243 const uint8_t *getPointer(void) const {
DuyLionTran 0:64ca984b3efd 244 return valueBytes;
DuyLionTran 0:64ca984b3efd 245 }
DuyLionTran 0:64ca984b3efd 246
DuyLionTran 0:64ca984b3efd 247 unsigned getNumValueBytes(void) const {
DuyLionTran 0:64ca984b3efd 248 if (valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) {
DuyLionTran 0:64ca984b3efd 249 return 1 + sizeof(uint16_t);
DuyLionTran 0:64ca984b3efd 250 }
DuyLionTran 0:64ca984b3efd 251 else {
DuyLionTran 0:64ca984b3efd 252 return 1 + sizeof(uint8_t);
DuyLionTran 0:64ca984b3efd 253 }
DuyLionTran 0:64ca984b3efd 254 }
DuyLionTran 0:64ca984b3efd 255
DuyLionTran 0:64ca984b3efd 256 private:
DuyLionTran 0:64ca984b3efd 257 uint8_t valueBytes[MAX_VALUE_BYTES];
DuyLionTran 0:64ca984b3efd 258 };
DuyLionTran 0:64ca984b3efd 259
DuyLionTran 0:64ca984b3efd 260
DuyLionTran 0:64ca984b3efd 261 protected:
DuyLionTran 0:64ca984b3efd 262 BLE &ble;
DuyLionTran 0:64ca984b3efd 263 TemperatureValueBytes temperatureValueByte;
DuyLionTran 1:9eadd2dc4b6e 264 HeartRateValueBytes hrmValueByte;
DuyLionTran 0:64ca984b3efd 265
DuyLionTran 0:64ca984b3efd 266 ReadOnlyGattCharacteristic<TemperatureValueBytes> tempMeasurement;
DuyLionTran 14:e6029b780879 267 // ReadOnlyGattCharacteristic<uint8_t> tempLocation;
DuyLionTran 14:e6029b780879 268 ReadWriteGattCharacteristic<uint8_t> tempLocation;
DuyLionTran 0:64ca984b3efd 269
DuyLionTran 2:16f6cfcd7505 270 GattCharacteristic hrmRate;
DuyLionTran 15:00a1c0ea570c 271 // ReadOnlyGattCharacteristic<uint8_t> hrmLocation;
DuyLionTran 15:00a1c0ea570c 272 ReadWriteGattCharacteristic<uint8_t> hrmLocation;
DuyLionTran 8:3384286a8498 273
DuyLionTran 8:3384286a8498 274 ReadWriteGattCharacteristic<uint8_t> controlState;
DuyLionTran 0:64ca984b3efd 275 };
DuyLionTran 0:64ca984b3efd 276
DuyLionTran 0:64ca984b3efd 277
DuyLionTran 0:64ca984b3efd 278 #endif /* __BLE_HEALTHCARE_SERVICE_H__ */