Graduation Thesis, use Nucleo and X-Nucleo BLE
Dependencies: PulseSensor GSM Thermometer KalmanFilter
application/ble_healthcare_service.h@1:9eadd2dc4b6e, 2018-02-14 (annotated)
- Committer:
- DuyLionTran
- Date:
- Wed Feb 14 01:29:53 2018 +0000
- Revision:
- 1:9eadd2dc4b6e
- Parent:
- 0:64ca984b3efd
- Child:
- 2:16f6cfcd7505
version 0.8 02-12-2018
Who changed what in which revision?
User | Revision | Line number | New 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 | 0:64ca984b3efd | 37 | }; |
DuyLionTran | 0:64ca984b3efd | 38 | |
DuyLionTran | 0:64ca984b3efd | 39 | public: |
DuyLionTran | 0:64ca984b3efd | 40 | /** |
DuyLionTran | 0:64ca984b3efd | 41 | * @param[in] _ble Reference to the BLE device. |
DuyLionTran | 0:64ca984b3efd | 42 | * @param[in] initialTemp Initial value in celsius. |
DuyLionTran | 0:64ca984b3efd | 43 | * @param[in] _tempLocation Location of the thermometer. |
DuyLionTran | 0:64ca984b3efd | 44 | * @param[in] hrmCounter Heart beats per minute measured by the heart rate sensor. |
DuyLionTran | 0:64ca984b3efd | 45 | * @param[in] _HRMlocation Intended location of the heart rate sensor. |
DuyLionTran | 0:64ca984b3efd | 46 | */ |
DuyLionTran | 0:64ca984b3efd | 47 | HealthCareService(BLE &_ble, |
DuyLionTran | 0:64ca984b3efd | 48 | float initialTemp, |
DuyLionTran | 0:64ca984b3efd | 49 | uint8_t _tempLocation, |
DuyLionTran | 0:64ca984b3efd | 50 | // ) : |
DuyLionTran | 1:9eadd2dc4b6e | 51 | uint8_t hrmCounter, |
DuyLionTran | 0:64ca984b3efd | 52 | uint8_t _hrmLocation) : |
DuyLionTran | 0:64ca984b3efd | 53 | ble(_ble), |
DuyLionTran | 0:64ca984b3efd | 54 | temperatureValueByte(initialTemp), |
DuyLionTran | 1:9eadd2dc4b6e | 55 | hrmValueByte(hrmCounter), |
DuyLionTran | 0:64ca984b3efd | 56 | tempMeasurement(GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, |
DuyLionTran | 0:64ca984b3efd | 57 | (TemperatureValueBytes *)temperatureValueByte.getPointer(), |
DuyLionTran | 0:64ca984b3efd | 58 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), |
DuyLionTran | 0:64ca984b3efd | 59 | tempLocation(GattCharacteristic::UUID_TEMPERATURE_TYPE_CHAR, |
DuyLionTran | 0:64ca984b3efd | 60 | &_tempLocation), |
DuyLionTran | 1:9eadd2dc4b6e | 61 | hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, |
DuyLionTran | 1:9eadd2dc4b6e | 62 | (HeartRateValueBytes *)hrmValueByte.getPointer(), |
DuyLionTran | 0:64ca984b3efd | 63 | // hrmValueByte.getNumValueBytes(), |
DuyLionTran | 0:64ca984b3efd | 64 | // HeartRateValueBytes::MAX_VALUE_BYTES, |
DuyLionTran | 1:9eadd2dc4b6e | 65 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), |
DuyLionTran | 0:64ca984b3efd | 66 | hrmLocation( |
DuyLionTran | 0:64ca984b3efd | 67 | GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, |
DuyLionTran | 0:64ca984b3efd | 68 | reinterpret_cast<uint8_t*>(&_hrmLocation)) |
DuyLionTran | 0:64ca984b3efd | 69 | |
DuyLionTran | 0:64ca984b3efd | 70 | { |
DuyLionTran | 1:9eadd2dc4b6e | 71 | GattCharacteristic *HealthCareChars[] = {&tempMeasurement, &tempLocation, &hrmRate,&hrmLocation}; |
DuyLionTran | 0:64ca984b3efd | 72 | GattService HealthCareService(GattService::UUID_HEART_RATE_SERVICE , HealthCareChars, sizeof(HealthCareChars) / sizeof(GattCharacteristic *)); |
DuyLionTran | 0:64ca984b3efd | 73 | |
DuyLionTran | 0:64ca984b3efd | 74 | ble.addService(HealthCareService); |
DuyLionTran | 0:64ca984b3efd | 75 | } |
DuyLionTran | 0:64ca984b3efd | 76 | |
DuyLionTran | 0:64ca984b3efd | 77 | /** |
DuyLionTran | 0:64ca984b3efd | 78 | * @brief Update the temperature being broadcast. |
DuyLionTran | 0:64ca984b3efd | 79 | * @param[in] temperature Floating point value of the temperature. |
DuyLionTran | 0:64ca984b3efd | 80 | */ |
DuyLionTran | 0:64ca984b3efd | 81 | void updateTemperature(float temperature) { |
DuyLionTran | 0:64ca984b3efd | 82 | if (ble.getGapState().connected) { |
DuyLionTran | 0:64ca984b3efd | 83 | temperatureValueByte.updateTemperature(temperature); |
DuyLionTran | 0:64ca984b3efd | 84 | ble.gattServer().write(tempMeasurement.getValueHandle(), temperatureValueByte.getPointer(), sizeof(TemperatureValueBytes)); |
DuyLionTran | 0:64ca984b3efd | 85 | } |
DuyLionTran | 0:64ca984b3efd | 86 | } |
DuyLionTran | 0:64ca984b3efd | 87 | |
DuyLionTran | 0:64ca984b3efd | 88 | /** |
DuyLionTran | 0:64ca984b3efd | 89 | * @brief Update the location. |
DuyLionTran | 0:64ca984b3efd | 90 | * @param loc New location value. |
DuyLionTran | 0:64ca984b3efd | 91 | */ |
DuyLionTran | 0:64ca984b3efd | 92 | void updateLocation(TemperatureSensorLocation_t loc) { |
DuyLionTran | 0:64ca984b3efd | 93 | ble.gattServer().write(tempLocation.getValueHandle(), reinterpret_cast<uint8_t *>(&loc), sizeof(uint8_t)); |
DuyLionTran | 0:64ca984b3efd | 94 | } |
DuyLionTran | 0:64ca984b3efd | 95 | |
DuyLionTran | 0:64ca984b3efd | 96 | /** |
DuyLionTran | 0:64ca984b3efd | 97 | * Update the heart rate that the service exposes. |
DuyLionTran | 0:64ca984b3efd | 98 | * The server sends a notification of the new value to clients that have |
DuyLionTran | 0:64ca984b3efd | 99 | * subscribed to updates of the heart rate measurement characteristic; clients |
DuyLionTran | 0:64ca984b3efd | 100 | * reading the heart rate measurement characteristic after the update obtain |
DuyLionTran | 0:64ca984b3efd | 101 | * the updated value. |
DuyLionTran | 0:64ca984b3efd | 102 | * |
DuyLionTran | 0:64ca984b3efd | 103 | * @param[in] hrmCounter Heart rate measured in BPM. |
DuyLionTran | 0:64ca984b3efd | 104 | * @attention This function must be called in the execution context of the BLE stack. |
DuyLionTran | 0:64ca984b3efd | 105 | */ |
DuyLionTran | 0:64ca984b3efd | 106 | void updateHeartRate(uint16_t hrmCounter) { |
DuyLionTran | 1:9eadd2dc4b6e | 107 | hrmValueByte.updateHeartRate(hrmCounter); |
DuyLionTran | 1:9eadd2dc4b6e | 108 | ble.gattServer().write( |
DuyLionTran | 1:9eadd2dc4b6e | 109 | hrmRate.getValueHandle(), |
DuyLionTran | 1:9eadd2dc4b6e | 110 | hrmValueByte.getPointer(), |
DuyLionTran | 1:9eadd2dc4b6e | 111 | hrmValueByte.getNumValueBytes() |
DuyLionTran | 1:9eadd2dc4b6e | 112 | ); |
DuyLionTran | 0:64ca984b3efd | 113 | } |
DuyLionTran | 0:64ca984b3efd | 114 | |
DuyLionTran | 0:64ca984b3efd | 115 | private: |
DuyLionTran | 0:64ca984b3efd | 116 | /* Private internal representation for the bytes used to work with the vaulue of the temperature characteristic. */ |
DuyLionTran | 0:64ca984b3efd | 117 | struct TemperatureValueBytes { |
DuyLionTran | 0:64ca984b3efd | 118 | static const unsigned OFFSET_OF_FLAGS = 0; |
DuyLionTran | 0:64ca984b3efd | 119 | static const unsigned OFFSET_OF_VALUE = OFFSET_OF_FLAGS + sizeof(uint8_t); |
DuyLionTran | 0:64ca984b3efd | 120 | static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float); |
DuyLionTran | 0:64ca984b3efd | 121 | |
DuyLionTran | 0:64ca984b3efd | 122 | static const unsigned TEMPERATURE_UNITS_FLAG_POS = 0; |
DuyLionTran | 0:64ca984b3efd | 123 | static const unsigned TIMESTAMP_FLAG_POS = 1; |
DuyLionTran | 0:64ca984b3efd | 124 | static const unsigned TEMPERATURE_TYPE_FLAG_POS = 2; |
DuyLionTran | 0:64ca984b3efd | 125 | |
DuyLionTran | 0:64ca984b3efd | 126 | static const uint8_t TEMPERATURE_UNITS_CELSIUS = 0; |
DuyLionTran | 0:64ca984b3efd | 127 | static const uint8_t TEMPERATURE_UNITS_FAHRENHEIT = 1; |
DuyLionTran | 0:64ca984b3efd | 128 | |
DuyLionTran | 0:64ca984b3efd | 129 | TemperatureValueBytes(float initialTemperature) : bytes() { |
DuyLionTran | 0:64ca984b3efd | 130 | /* Assumption: temperature values are expressed in celsius */ |
DuyLionTran | 0:64ca984b3efd | 131 | bytes[OFFSET_OF_FLAGS] = (TEMPERATURE_UNITS_CELSIUS << TEMPERATURE_UNITS_FLAG_POS) | |
DuyLionTran | 0:64ca984b3efd | 132 | (false << TIMESTAMP_FLAG_POS) | |
DuyLionTran | 0:64ca984b3efd | 133 | (false << TEMPERATURE_TYPE_FLAG_POS); |
DuyLionTran | 0:64ca984b3efd | 134 | updateTemperature(initialTemperature); |
DuyLionTran | 0:64ca984b3efd | 135 | } |
DuyLionTran | 0:64ca984b3efd | 136 | |
DuyLionTran | 0:64ca984b3efd | 137 | void updateTemperature(float temp) { |
DuyLionTran | 0:64ca984b3efd | 138 | uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp); |
DuyLionTran | 0:64ca984b3efd | 139 | memcpy(&bytes[OFFSET_OF_VALUE], &temp_ieee11073, sizeof(float)); |
DuyLionTran | 0:64ca984b3efd | 140 | } |
DuyLionTran | 0:64ca984b3efd | 141 | |
DuyLionTran | 0:64ca984b3efd | 142 | uint8_t *getPointer(void) { |
DuyLionTran | 0:64ca984b3efd | 143 | return bytes; |
DuyLionTran | 0:64ca984b3efd | 144 | } |
DuyLionTran | 0:64ca984b3efd | 145 | |
DuyLionTran | 0:64ca984b3efd | 146 | const uint8_t *getPointer(void) const { |
DuyLionTran | 0:64ca984b3efd | 147 | return bytes; |
DuyLionTran | 0:64ca984b3efd | 148 | } |
DuyLionTran | 0:64ca984b3efd | 149 | |
DuyLionTran | 0:64ca984b3efd | 150 | private: |
DuyLionTran | 0:64ca984b3efd | 151 | /** |
DuyLionTran | 0:64ca984b3efd | 152 | * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type. |
DuyLionTran | 0:64ca984b3efd | 153 | * @param temperature The temperature as a float. |
DuyLionTran | 0:64ca984b3efd | 154 | * @return The temperature in 11073-20601 FLOAT-Type format. |
DuyLionTran | 0:64ca984b3efd | 155 | */ |
DuyLionTran | 0:64ca984b3efd | 156 | uint32_t quick_ieee11073_from_float(float temperature) { |
DuyLionTran | 0:64ca984b3efd | 157 | uint8_t exponent = 0xFE; //Exponent is -2 |
DuyLionTran | 0:64ca984b3efd | 158 | uint32_t mantissa = (uint32_t)(temperature * 100); |
DuyLionTran | 0:64ca984b3efd | 159 | |
DuyLionTran | 0:64ca984b3efd | 160 | return (((uint32_t)exponent) << 24) | mantissa; |
DuyLionTran | 0:64ca984b3efd | 161 | } |
DuyLionTran | 0:64ca984b3efd | 162 | |
DuyLionTran | 0:64ca984b3efd | 163 | private: |
DuyLionTran | 0:64ca984b3efd | 164 | /* First byte: 8-bit flags. Second field is a float holding the temperature value. */ |
DuyLionTran | 0:64ca984b3efd | 165 | /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */ |
DuyLionTran | 0:64ca984b3efd | 166 | uint8_t bytes[SIZEOF_VALUE_BYTES]; |
DuyLionTran | 0:64ca984b3efd | 167 | }; |
DuyLionTran | 0:64ca984b3efd | 168 | |
DuyLionTran | 0:64ca984b3efd | 169 | protected: |
DuyLionTran | 0:64ca984b3efd | 170 | /* |
DuyLionTran | 0:64ca984b3efd | 171 | * Heart rate measurement value. |
DuyLionTran | 0:64ca984b3efd | 172 | */ |
DuyLionTran | 0:64ca984b3efd | 173 | struct HeartRateValueBytes { |
DuyLionTran | 0:64ca984b3efd | 174 | /* 1 byte for the Flags, and up to two bytes for heart rate value. */ |
DuyLionTran | 0:64ca984b3efd | 175 | static const unsigned MAX_VALUE_BYTES = 3; |
DuyLionTran | 0:64ca984b3efd | 176 | static const unsigned FLAGS_BYTE_INDEX = 0; |
DuyLionTran | 0:64ca984b3efd | 177 | |
DuyLionTran | 0:64ca984b3efd | 178 | static const unsigned VALUE_FORMAT_BITNUM = 0; |
DuyLionTran | 0:64ca984b3efd | 179 | static const uint8_t VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM); |
DuyLionTran | 0:64ca984b3efd | 180 | |
DuyLionTran | 0:64ca984b3efd | 181 | HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() { |
DuyLionTran | 0:64ca984b3efd | 182 | updateHeartRate(hrmCounter); |
DuyLionTran | 0:64ca984b3efd | 183 | } |
DuyLionTran | 0:64ca984b3efd | 184 | |
DuyLionTran | 0:64ca984b3efd | 185 | void updateHeartRate(uint16_t hrmCounter) { |
DuyLionTran | 0:64ca984b3efd | 186 | if (hrmCounter <= 255) { |
DuyLionTran | 0:64ca984b3efd | 187 | valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG; |
DuyLionTran | 0:64ca984b3efd | 188 | valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter; |
DuyLionTran | 0:64ca984b3efd | 189 | } else { |
DuyLionTran | 0:64ca984b3efd | 190 | valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG; |
DuyLionTran | 0:64ca984b3efd | 191 | valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF); |
DuyLionTran | 0:64ca984b3efd | 192 | valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8); |
DuyLionTran | 0:64ca984b3efd | 193 | } |
DuyLionTran | 0:64ca984b3efd | 194 | } |
DuyLionTran | 0:64ca984b3efd | 195 | |
DuyLionTran | 0:64ca984b3efd | 196 | uint8_t *getPointer(void) { |
DuyLionTran | 0:64ca984b3efd | 197 | return valueBytes; |
DuyLionTran | 0:64ca984b3efd | 198 | } |
DuyLionTran | 0:64ca984b3efd | 199 | |
DuyLionTran | 0:64ca984b3efd | 200 | const uint8_t *getPointer(void) const { |
DuyLionTran | 0:64ca984b3efd | 201 | return valueBytes; |
DuyLionTran | 0:64ca984b3efd | 202 | } |
DuyLionTran | 0:64ca984b3efd | 203 | |
DuyLionTran | 0:64ca984b3efd | 204 | unsigned getNumValueBytes(void) const { |
DuyLionTran | 0:64ca984b3efd | 205 | if (valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) { |
DuyLionTran | 0:64ca984b3efd | 206 | return 1 + sizeof(uint16_t); |
DuyLionTran | 0:64ca984b3efd | 207 | } |
DuyLionTran | 0:64ca984b3efd | 208 | else { |
DuyLionTran | 0:64ca984b3efd | 209 | return 1 + sizeof(uint8_t); |
DuyLionTran | 0:64ca984b3efd | 210 | } |
DuyLionTran | 0:64ca984b3efd | 211 | } |
DuyLionTran | 0:64ca984b3efd | 212 | |
DuyLionTran | 0:64ca984b3efd | 213 | private: |
DuyLionTran | 0:64ca984b3efd | 214 | uint8_t valueBytes[MAX_VALUE_BYTES]; |
DuyLionTran | 0:64ca984b3efd | 215 | }; |
DuyLionTran | 0:64ca984b3efd | 216 | |
DuyLionTran | 0:64ca984b3efd | 217 | |
DuyLionTran | 0:64ca984b3efd | 218 | protected: |
DuyLionTran | 0:64ca984b3efd | 219 | BLE &ble; |
DuyLionTran | 0:64ca984b3efd | 220 | TemperatureValueBytes temperatureValueByte; |
DuyLionTran | 1:9eadd2dc4b6e | 221 | HeartRateValueBytes hrmValueByte; |
DuyLionTran | 0:64ca984b3efd | 222 | |
DuyLionTran | 0:64ca984b3efd | 223 | ReadOnlyGattCharacteristic<TemperatureValueBytes> tempMeasurement; |
DuyLionTran | 0:64ca984b3efd | 224 | ReadOnlyGattCharacteristic<uint8_t> tempLocation; |
DuyLionTran | 0:64ca984b3efd | 225 | |
DuyLionTran | 1:9eadd2dc4b6e | 226 | ReadOnlyGattCharacteristic<HeartRateValueBytes> hrmRate; |
DuyLionTran | 0:64ca984b3efd | 227 | ReadOnlyGattCharacteristic<uint8_t> hrmLocation; |
DuyLionTran | 0:64ca984b3efd | 228 | }; |
DuyLionTran | 0:64ca984b3efd | 229 | |
DuyLionTran | 0:64ca984b3efd | 230 | |
DuyLionTran | 0:64ca984b3efd | 231 | #endif /* __BLE_HEALTHCARE_SERVICE_H__ */ |