Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nRF5-DK-HeartRateDemo by
HeartRateService.h
00001 /* Preface: 00002 This is the HeartRateService from the mbed Microcontroller library. 00003 Copied from https://github.com/ARMmbed/mbed-os/blob/master/features/FEATURE_BLE/ble/services/HeartRateService.h 00004 (2259e0d) 00005 00006 The source has not been changed, but comments have been added to help clarify: 00007 Behavior, 00008 C++ Syntax, and 00009 Design decisions 00010 00011 Added comments are all in-line comments that start with: 00012 // COMMENT: 00013 00014 00015 */ 00016 00017 /* mbed Microcontroller Library 00018 * Copyright (c) 2006-2013 ARM Limited 00019 * 00020 * Licensed under the Apache License, Version 2.0 (the "License"); 00021 * you may not use this file except in compliance with the License. 00022 * You may obtain a copy of the License at 00023 * 00024 * http://www.apache.org/licenses/LICENSE-2.0 00025 * 00026 * Unless required by applicable law or agreed to in writing, software 00027 * distributed under the License is distributed on an "AS IS" BASIS, 00028 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00029 * See the License for the specific language governing permissions and 00030 * limitations under the License. 00031 */ 00032 00033 #ifndef __BLE_HEART_RATE_SERVICE_H__ 00034 #define __BLE_HEART_RATE_SERVICE_H__ 00035 00036 #include "ble/BLE.h" 00037 00038 /** 00039 * @class HeartRateService 00040 * @brief BLE Service for HeartRate. This BLE Service contains the location of the sensor and the heart rate in beats per minute. 00041 * Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml 00042 * HRM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml 00043 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml 00044 */ 00045 00046 // COMMENT: It would be wise to review the definition of the HeartRateService 00047 // COMMENT: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml 00048 // COMMENT: Note that it contains three characteristics: The Heart Rate Measurement, the Body Sensor Location, and the Heart Rate Cotrol Point. 00049 class HeartRateService { 00050 00051 // COMMENT: C++ uses the labels public: , private: , and protected: to control scope. 00052 // COMMENT: The scope applies to everything until the next scope label. 00053 public: 00054 /** 00055 * @enum SensorLocation 00056 * @brief Location of the heart rate sensor on body. 00057 */ 00058 enum { 00059 LOCATION_OTHER = 0, /*!< Other location. */ 00060 LOCATION_CHEST , /*!< Chest. */ 00061 LOCATION_WRIST , /*!< Wrist. */ 00062 LOCATION_FINGER , /*!< Finger. */ 00063 LOCATION_HAND , /*!< Hand. */ 00064 LOCATION_EAR_LOBE , /*!< Earlobe. */ 00065 LOCATION_FOOT , /*!< Foot. */ 00066 }; 00067 00068 public: 00069 /** 00070 * @brief Constructor with 8-bit HRM Counter value. 00071 * 00072 * @param[ref] _ble 00073 * Reference to the underlying BLE. 00074 * @param[in] hrmCounter (8-bit) 00075 * Initial value for the HRM counter. 00076 * @param[in] location 00077 * Sensor's location. 00078 */ 00079 HeartRateService(BLE &_ble, uint8_t hrmCounter, uint8_t location) : 00080 // COMMENT: This declares a constructor. The "BLE &_ble" parameter is an reference variable. 00081 // COMMENT: Reference variables are a way to efficiently pass and use an object while limiting the way 00082 // COMMENT: it can be changed. See: https://en.wikipedia.org/wiki/Reference_(C%2B%2B) for more. 00083 00084 // COMMENT: The lines below are a way to efficiently initialize the fields (aka instance variables) of the 00085 // COMMENT: object. In Java this is often done with several assignments in the body of the constructor. 00086 // COMMENT: Ex: "valueBytes = hrmCounter;" within the function rather than "valueBytes(hrmCounter)" before 00087 // COMMENT: the function begins. (The behavior of the approach used here can be subtly different with C++ 00088 // COMMENT: objects and references) 00089 // COMMENT: See: http://www.cprogramming.com/tutorial/initialization-lists-c++.html for more on initialization lists 00090 ble(_ble), 00091 valueBytes(hrmCounter), 00092 // COMMENT: The hrmRate is declared as a "GattCharacteristic", which doesn't have any properties by default. 00093 // COMMENT: Notice that READ and NOTIFY properties are being passed into the constructor to allow read/notify. 00094 hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(), 00095 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES, 00096 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), 00097 hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location), 00098 controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) { 00099 // COMMENT: This is the body of the method. It just calls a private method to complete the setup. 00100 // COMMENT: This was done so all constructors could use this same method for common setup steps 00101 // COMMENT: (rather than replicate the code in each constructor) 00102 setupService(); 00103 } 00104 00105 /** 00106 * @brief Constructor with a 16-bit HRM Counter value. 00107 * 00108 * @param[in] _ble 00109 * Reference to the underlying BLE. 00110 * @param[in] hrmCounter (8-bit) 00111 * Initial value for the HRM counter. 00112 * @param[in] location 00113 * Sensor's location. 00114 */ 00115 // COMMENT: Another constructor. 00116 HeartRateService(BLE &_ble, uint16_t hrmCounter, uint8_t location) : 00117 ble(_ble), 00118 valueBytes(hrmCounter), 00119 hrmRate(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR, valueBytes.getPointer(), 00120 valueBytes.getNumValueBytes(), HeartRateValueBytes::MAX_VALUE_BYTES, 00121 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), 00122 hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR, &location), 00123 controlPoint(GattCharacteristic::UUID_HEART_RATE_CONTROL_POINT_CHAR, &controlPointValue) { 00124 setupService(); 00125 } 00126 00127 /** 00128 * @brief Set a new 8-bit value for the heart rate. 00129 * 00130 * @param[in] hrmCounter 00131 * Heart rate in BPM. 00132 */ 00133 void updateHeartRate(uint8_t hrmCounter) { 00134 // COMMENT: This is method that will be used to update the value of the heart rate characteristic. 00135 // COMMENT: valueBytes is the actual characteristic. The following line of code will update its value. 00136 valueBytes.updateHeartRate(hrmCounter); 00137 // COMMENT: But valueBytes is just the member variable in this object for the heart rate. The BLE subsystem 00138 // COMMENT: needs to be notified that it has changed (so a notification can be sent) 00139 // COMMENT: This is changing an "Attribute's value". The BLE Server has it's own internal copy of all the 00140 // COMMENT: data. The following line of code will update this internal copy: 00141 ble.gattServer().write(hrmRate.getValueHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes()); 00142 // COMMENT: I.e., the server write to the heart rate characteristic's "value" by using the designated number of bytes. 00143 // COMMENT: "pointers" are used to copy the data. For more on pointers see: https://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays 00144 } 00145 00146 /** 00147 * Set a new 16-bit value for the heart rate. 00148 * 00149 * @param[in] hrmCounter 00150 * Heart rate in BPM. 00151 */ 00152 void updateHeartRate(uint16_t hrmCounter) { 00153 // COMMENT: Like the above, but using a 16-bit value instead. 00154 valueBytes.updateHeartRate(hrmCounter); 00155 ble.gattServer().write(hrmRate.getValueHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes()); 00156 } 00157 00158 /** 00159 * This callback allows the heart rate service to receive updates to the 00160 * controlPoint characteristic. 00161 * 00162 * @param[in] params 00163 * Information about the characterisitc being updated. 00164 */ 00165 virtual void onDataWritten(const GattWriteCallbackParams *params) { 00166 if (params->handle == controlPoint.getValueAttribute().getHandle()) { 00167 // COMMENT: This is a virtual function --- It could be "overridden" by a subclass. 00168 // COMMENT: The if-statement would allow this code to determine if a change had been 00169 // COMMENT: to the control point (the code to react to that change could be placed here) 00170 // COMMENT: This callback must be "connected" to the BLE stack (this is done in the setupService()) 00171 /* Do something here if the new value is 1; else you can override this method by 00172 * extending this class. 00173 * @NOTE: If you are extending this class, be sure to also call 00174 * ble.onDataWritten(this, &ExtendedHRService::onDataWritten); in 00175 * your constructor. 00176 */ 00177 } 00178 } 00179 00180 protected: 00181 void setupService(void) { 00182 // COMMENT: This builds the service table (an array of the individual characteristics) 00183 // COMMENT: Note the use of the "address-of" operation (&) to build the table. See: http://www.cplusplus.com/doc/tutorial/pointers/ 00184 GattCharacteristic *charTable[] = {&hrmRate, &hrmLocation, &controlPoint}; 00185 GattService hrmService(GattService::UUID_HEART_RATE_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); 00186 00187 ble.addService(hrmService); 00188 // COMMENT: This setups up the "onDataWritten" callback above. I.e., it adds in a way to 00189 // COMMENT: respond when data is written to the BLE stack from the client. 00190 ble.onDataWritten(this, &HeartRateService::onDataWritten); 00191 } 00192 00193 protected: 00194 /* Private internal representation for the bytes used to work with the value of the heart rate characteristic. */ 00195 // COMMENT: This "struct" is like having another class nested (with all public member fields/methods) 00196 // COMMENT: The Heart Rate Service can use two different formats for the heart rate data. This hides 00197 // COMMENT: the details of which is being used. 00198 struct HeartRateValueBytes { 00199 static const unsigned MAX_VALUE_BYTES = 3; /* Flags, and up to two bytes for heart rate. */ 00200 static const unsigned FLAGS_BYTE_INDEX = 0; 00201 00202 static const unsigned VALUE_FORMAT_BITNUM = 0; 00203 static const uint8_t VALUE_FORMAT_FLAG = (1 << VALUE_FORMAT_BITNUM); 00204 00205 // The following two constructors allow objects to be constructed from either 8-bit or 16-bit values. 00206 HeartRateValueBytes(uint8_t hrmCounter) : valueBytes() { 00207 updateHeartRate(hrmCounter); 00208 } 00209 00210 HeartRateValueBytes(uint16_t hrmCounter) : valueBytes() { 00211 updateHeartRate(hrmCounter); 00212 } 00213 00214 // COMMENT: This will allow an update of the data from an 8-bit value (for the 8-bit format) 00215 void updateHeartRate(uint8_t hrmCounter) { 00216 valueBytes[FLAGS_BYTE_INDEX] &= ~VALUE_FORMAT_FLAG; 00217 valueBytes[FLAGS_BYTE_INDEX + 1] = hrmCounter; 00218 } 00219 00220 // COMMENT: This will allow an update of the data from an 16-bit value (for the 16-bit format) 00221 void updateHeartRate(uint16_t hrmCounter) { 00222 valueBytes[FLAGS_BYTE_INDEX] |= VALUE_FORMAT_FLAG; 00223 valueBytes[FLAGS_BYTE_INDEX + 1] = (uint8_t)(hrmCounter & 0xFF); 00224 valueBytes[FLAGS_BYTE_INDEX + 2] = (uint8_t)(hrmCounter >> 8); 00225 } 00226 // COMMENT: The two "getPointer()" functions allow access to the stored heart rate data via pointers. 00227 // COMMENT: See: https://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays for details of pointers 00228 uint8_t *getPointer(void) { 00229 return valueBytes; 00230 } 00231 00232 const uint8_t *getPointer(void) const { 00233 return valueBytes; 00234 } 00235 00236 // COMMENT: The following getter will get the actual bytes promoted to a 32-bit unsigned. 00237 unsigned getNumValueBytes(void) const { 00238 return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & VALUE_FORMAT_FLAG) ? sizeof(uint16_t) : sizeof(uint8_t)); 00239 } 00240 00241 private: 00242 /* First byte: 8-bit values, no extra info. Second byte: uint8_t HRM value */ 00243 /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */ 00244 // COMMENT: The actual bytes are protected/hidden from direct access. 00245 uint8_t valueBytes[MAX_VALUE_BYTES]; 00246 }; 00247 00248 protected: 00249 // COMMENT: These are the fields (aka properties aka instance variables) of the object. 00250 // COMMENT: The ble variable is used to access the entire BLE subsystem (GAP and GATT layers of the stack) 00251 BLE &ble; 00252 00253 // COMMENT: Use a "HeartRateValueBytes" object to keep track of the heart rate 00254 // COMMENT: (This hide the details of how it is actually stored) 00255 HeartRateValueBytes valueBytes; 00256 // COMMENT: the controlPointValue represents the value of the control point. 00257 uint8_t controlPointValue; 00258 00259 // COMMENT: The following three variables declare the actual characteristics 00260 GattCharacteristic hrmRate; 00261 ReadOnlyGattCharacteristic<uint8_t> hrmLocation; 00262 // COMMENT: The ReadOnlyGattCharacteristic uses templates (like Java's Generics) to specify the data type that will be used. 00263 // COMMENT: In these cases a single byte will be used for both the hrmLocation and controlPoint characteristics. 00264 WriteOnlyGattCharacteristic<uint8_t> controlPoint; 00265 00266 // COMMENT: Notice that characteristics were declared with three different types: 00267 // COMMENT: Just "GattCharacteristic", which needs to have the data & properties specified in the constructor. 00268 // COMMENT: As "ReadOnlyGattCharacteristic", which will be readable (only) 00269 // COMMENT: And as "WriteOnlyGattCharacteristic", which will be writeabel (only) 00270 }; 00271 00272 #endif /* #ifndef __BLE_HEART_RATE_SERVICE_H__*/
Generated on Wed Jul 13 2022 09:59:17 by
1.7.2
