Icarus Sensors / Mbed 2 deprecated Cycle_Speed_Cadence_Service

Dependencies:   BLE_API mbed nRF51822

Fork of Bluetooth_Heart_Rate_Monitor_dummy by Icarus Sensors

Committer:
balczezzz
Date:
Mon May 04 21:55:15 2015 +0000
Revision:
62:2ea9997b5249
Parent:
61:16f888838853
Child:
64:43e7ddf9dba5
small tweaks

Who changed what in which revision?

UserRevisionLine numberNew contents of line
smigielski 61:16f888838853 1 /* mbed Microcontroller Library
smigielski 61:16f888838853 2 * Copyright (c) 2006-2013 ARM Limited
smigielski 61:16f888838853 3 *
smigielski 61:16f888838853 4 * Licensed under the Apache License, Version 2.0 (the "License");
smigielski 61:16f888838853 5 * you may not use this file except in compliance with the License.
smigielski 61:16f888838853 6 * You may obtain a copy of the License at
smigielski 61:16f888838853 7 *
smigielski 61:16f888838853 8 * http://www.apache.org/licenses/LICENSE-2.0
smigielski 61:16f888838853 9 *
smigielski 61:16f888838853 10 * Unless required by applicable law or agreed to in writing, software
smigielski 61:16f888838853 11 * distributed under the License is distributed on an "AS IS" BASIS,
smigielski 61:16f888838853 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
smigielski 61:16f888838853 13 * See the License for the specific language governing permissions and
smigielski 61:16f888838853 14 * limitations under the License.
smigielski 61:16f888838853 15 */
smigielski 61:16f888838853 16
smigielski 61:16f888838853 17 #ifndef __BLE_CYCLE_SPEED_CADENCE_SERVICE_H__
smigielski 61:16f888838853 18 #define __BLE_CYCLE_SPEED_CADENCE_SERVICE_H__
smigielski 61:16f888838853 19
smigielski 61:16f888838853 20 #include "BLEDevice.h"
smigielski 61:16f888838853 21
smigielski 61:16f888838853 22 /**
smigielski 61:16f888838853 23 * @class CycleSpeedCadenceService
smigielski 61:16f888838853 24 * @brief BLE Service for HeartRate. This BLE Service contains the location of the sensor, the heartrate in beats per minute. <br>
smigielski 61:16f888838853 25 * Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml <br>
smigielski 61:16f888838853 26 * HRM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml <br>
smigielski 61:16f888838853 27 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml
smigielski 61:16f888838853 28 */
smigielski 61:16f888838853 29 class CycleSpeedCadenceService {
smigielski 61:16f888838853 30 public:
smigielski 61:16f888838853 31 /**
smigielski 61:16f888838853 32 * @enum SensorLocation
smigielski 61:16f888838853 33 * @brief Location of HeartRate sensor on body.
smigielski 61:16f888838853 34 */
smigielski 61:16f888838853 35 enum {
smigielski 61:16f888838853 36 LOCATION_OTHER = 0,
smigielski 61:16f888838853 37 LOCATION_TOP_OF_SHOE,
smigielski 61:16f888838853 38 LOCATION_IN_SHOE,
smigielski 61:16f888838853 39 LOCATION_HIP,
smigielski 61:16f888838853 40 LOCATION_FRONT_WHEEL,
smigielski 61:16f888838853 41 LOCATION_LEFT_CRANK,
smigielski 61:16f888838853 42 LOCATION_RIGHT_CRANK,
smigielski 61:16f888838853 43 LOCATION_LEFT_PEDAL,
smigielski 61:16f888838853 44 LOCATION_RIGHT_PEDAL,
smigielski 61:16f888838853 45 LOCATION_FRONT_HUB,
smigielski 61:16f888838853 46 LOCATION_REAR_DROPOUT,
smigielski 61:16f888838853 47 LOCATION_CHAINSTAY,
smigielski 61:16f888838853 48 LOCATION_REAR_WHEEL,
smigielski 61:16f888838853 49 LOCATION_REAR_HUB,
smigielski 61:16f888838853 50 LOCATION_CHEST
smigielski 61:16f888838853 51 };
smigielski 61:16f888838853 52
smigielski 61:16f888838853 53 enum {
smigielski 61:16f888838853 54 UUID_SENSOR_LOCATION_CHAR = 0x2A5D,
smigielski 61:16f888838853 55 UUID_CSC_MEASUREMENT_CHAR = 0x2A5B,
balczezzz 62:2ea9997b5249 56 UUID_CSC_FEATURE_CHAR = 0x2A5C,
balczezzz 62:2ea9997b5249 57 UUID_CSC_CONTROL_POINT_CHAR = 0x2A55
smigielski 61:16f888838853 58 };
smigielski 61:16f888838853 59
smigielski 61:16f888838853 60
smigielski 61:16f888838853 61
smigielski 61:16f888838853 62 public:
smigielski 61:16f888838853 63 /**
smigielski 61:16f888838853 64 * @brief Constructor with 8bit HRM Counter value.
smigielski 61:16f888838853 65 *
smigielski 61:16f888838853 66 * @param[ref] _ble
smigielski 61:16f888838853 67 * Reference to the underlying BLEDevice.
smigielski 61:16f888838853 68 * @param[in] hrmCounter (8-bit)
smigielski 61:16f888838853 69 * initial value for the hrm counter.
smigielski 61:16f888838853 70 * @param[in] location
smigielski 61:16f888838853 71 * Sensor's location.
smigielski 61:16f888838853 72 */
smigielski 61:16f888838853 73 CycleSpeedCadenceService(BLEDevice &_ble, uint32_t wheelRevolutions ,uint16_t wheelEvent, uint8_t location, bool locationSupport) :
smigielski 61:16f888838853 74 ble(_ble),
smigielski 61:16f888838853 75 feautureBytes(true,false,locationSupport),
smigielski 61:16f888838853 76 valueBytes(wheelRevolutions,wheelEvent),
smigielski 61:16f888838853 77 cscMesurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, valueBytes.getPointer(),
smigielski 61:16f888838853 78 valueBytes.getNumValueBytes(), CSCValueBytes::MAX_VALUE_BYTES,
smigielski 61:16f888838853 79 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
smigielski 61:16f888838853 80 cscFeatures(CycleSpeedCadenceService::UUID_CSC_FEATURE_CHAR, feautureBytes.getPointer()),
smigielski 61:16f888838853 81 sensorLocation(CycleSpeedCadenceService::UUID_SENSOR_LOCATION_CHAR, &location),
balczezzz 62:2ea9997b5249 82 controlPoint(CycleSpeedCadenceService::UUID_CSC_CONTROL_POINT_CHAR, &controlPointValue) {
smigielski 61:16f888838853 83 setupService();
smigielski 61:16f888838853 84 }
smigielski 61:16f888838853 85
smigielski 61:16f888838853 86 CycleSpeedCadenceService(BLEDevice &_ble, uint16_t crankRevolutions, uint16_t crankEvent, uint8_t location, bool locationSupport ) :
smigielski 61:16f888838853 87 ble(_ble),
smigielski 61:16f888838853 88 feautureBytes(false,true,locationSupport),
smigielski 61:16f888838853 89 valueBytes(crankRevolutions,crankEvent),
smigielski 61:16f888838853 90 cscMesurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, valueBytes.getPointer(),
smigielski 61:16f888838853 91 valueBytes.getNumValueBytes(), CSCValueBytes::MAX_VALUE_BYTES,
smigielski 61:16f888838853 92 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
smigielski 61:16f888838853 93 cscFeatures(CycleSpeedCadenceService::UUID_CSC_FEATURE_CHAR, feautureBytes.getPointer()),
smigielski 61:16f888838853 94 sensorLocation(CycleSpeedCadenceService::UUID_SENSOR_LOCATION_CHAR, &location),
balczezzz 62:2ea9997b5249 95 controlPoint(CycleSpeedCadenceService::UUID_CSC_CONTROL_POINT_CHAR, &controlPointValue) {
smigielski 61:16f888838853 96 setupService();
smigielski 61:16f888838853 97 }
smigielski 61:16f888838853 98
smigielski 61:16f888838853 99 CycleSpeedCadenceService(BLEDevice &_ble, uint32_t wheelRevolutions ,uint16_t wheelEvent,uint16_t crankRevolutions, uint16_t crankEvent, uint8_t location,bool locationSupport ) :
smigielski 61:16f888838853 100 ble(_ble),
smigielski 61:16f888838853 101 feautureBytes(true,true,locationSupport),
smigielski 61:16f888838853 102 valueBytes(wheelRevolutions,wheelEvent,crankRevolutions,crankEvent),
smigielski 61:16f888838853 103 cscMesurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, valueBytes.getPointer(),
smigielski 61:16f888838853 104 valueBytes.getNumValueBytes(), CSCValueBytes::MAX_VALUE_BYTES,
smigielski 61:16f888838853 105 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
smigielski 61:16f888838853 106 cscFeatures(CycleSpeedCadenceService::UUID_CSC_FEATURE_CHAR, feautureBytes.getPointer()),
smigielski 61:16f888838853 107 sensorLocation(CycleSpeedCadenceService::UUID_SENSOR_LOCATION_CHAR, &location),
balczezzz 62:2ea9997b5249 108 controlPoint(CycleSpeedCadenceService::UUID_CSC_CONTROL_POINT_CHAR, &controlPointValue) {
smigielski 61:16f888838853 109 setupService();
smigielski 61:16f888838853 110 }
smigielski 61:16f888838853 111
smigielski 61:16f888838853 112 /**
smigielski 61:16f888838853 113 * @brief Set a new 8-bit value for heart rate.
smigielski 61:16f888838853 114 *
smigielski 61:16f888838853 115 * @param[in] hrmCounter
smigielski 61:16f888838853 116 * HeartRate in bpm.
smigielski 61:16f888838853 117 */
smigielski 61:16f888838853 118 void updateWheel(uint32_t wheelRevolutions ,uint16_t wheelEvent) {
smigielski 61:16f888838853 119 valueBytes.updateWheel(wheelRevolutions,wheelEvent);
smigielski 61:16f888838853 120 ble.updateCharacteristicValue(cscMesurement.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
smigielski 61:16f888838853 121 }
smigielski 61:16f888838853 122
smigielski 61:16f888838853 123 /**
smigielski 61:16f888838853 124 * Set a new 16-bit value for heart rate.
smigielski 61:16f888838853 125 *
smigielski 61:16f888838853 126 * @param[in] hrmCounter
smigielski 61:16f888838853 127 * HeartRate in bpm.
smigielski 61:16f888838853 128 */
smigielski 61:16f888838853 129 void updateCrank(uint16_t crankRevolutions, uint16_t crankEvent) {
smigielski 61:16f888838853 130 valueBytes.updateCrank(crankRevolutions,crankEvent);
smigielski 61:16f888838853 131 ble.updateCharacteristicValue(cscMesurement.getValueAttribute().getHandle(), valueBytes.getPointer(), valueBytes.getNumValueBytes());
smigielski 61:16f888838853 132 }
smigielski 61:16f888838853 133
smigielski 61:16f888838853 134 /**
smigielski 61:16f888838853 135 * This callback allows the CycleSpeedCadenceService to receive updates to the
smigielski 61:16f888838853 136 * controlPoint Characteristic.
smigielski 61:16f888838853 137 *
smigielski 61:16f888838853 138 * @param[in] params
smigielski 61:16f888838853 139 * Information about the characterisitc being updated.
smigielski 61:16f888838853 140 */
smigielski 61:16f888838853 141 virtual void onDataWritten(const GattCharacteristicWriteCBParams *params) {
smigielski 61:16f888838853 142 if (params->charHandle == controlPoint.getValueAttribute().getHandle()) {
smigielski 61:16f888838853 143 /* Do something here if the new value is 1; else you can override this method by
smigielski 61:16f888838853 144 * extending this class.
smigielski 61:16f888838853 145 * @NOTE: if you are extending this class, be sure to also call
smigielski 61:16f888838853 146 * ble.onDataWritten(this, &ExtendedHRService::onDataWritten); in
smigielski 61:16f888838853 147 * your constructor.
smigielski 61:16f888838853 148 */
smigielski 61:16f888838853 149 }
smigielski 61:16f888838853 150 }
smigielski 61:16f888838853 151
smigielski 61:16f888838853 152 private:
smigielski 61:16f888838853 153 void setupService(void) {
smigielski 61:16f888838853 154 static bool serviceAdded = false; /* We should only ever need to add the heart rate service once. */
smigielski 61:16f888838853 155 if (serviceAdded) {
smigielski 61:16f888838853 156 return;
smigielski 61:16f888838853 157 }
smigielski 61:16f888838853 158
smigielski 61:16f888838853 159 GattCharacteristic *charTable[] = {&cscMesurement, &cscFeatures, &sensorLocation, &controlPoint};
smigielski 61:16f888838853 160 GattService cscsService(GattService::UUID_CYCLING_SPEED_AND_CADENCE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
smigielski 61:16f888838853 161
smigielski 61:16f888838853 162 ble.addService(cscsService);
smigielski 61:16f888838853 163 serviceAdded = true;
smigielski 61:16f888838853 164
smigielski 61:16f888838853 165 ble.onDataWritten(this, &CycleSpeedCadenceService::onDataWritten);
smigielski 61:16f888838853 166 }
smigielski 61:16f888838853 167
smigielski 61:16f888838853 168 private:
smigielski 61:16f888838853 169 struct CSCFeatureBytes {
smigielski 61:16f888838853 170 uint16_t cscFeaturesValue;
smigielski 61:16f888838853 171
smigielski 61:16f888838853 172 CSCFeatureBytes(bool wheelSupport, bool crankSupport, bool locationSupport){
smigielski 61:16f888838853 173 cscFeaturesValue= wheelSupport | crankSupport << 1 | locationSupport << 2;
smigielski 61:16f888838853 174 }
smigielski 61:16f888838853 175
smigielski 61:16f888838853 176 uint16_t *getPointer(void) {
smigielski 61:16f888838853 177 return &cscFeaturesValue;
smigielski 61:16f888838853 178 }
smigielski 61:16f888838853 179
smigielski 61:16f888838853 180 const uint16_t *getPointer(void) const {
smigielski 61:16f888838853 181 return &cscFeaturesValue;
smigielski 61:16f888838853 182 }
smigielski 61:16f888838853 183 };
smigielski 61:16f888838853 184 /* Private internal representation for the bytes used to work with the vaulue of the heart-rate characteristic. */
smigielski 61:16f888838853 185 struct CSCValueBytes {
smigielski 61:16f888838853 186 static const unsigned MAX_VALUE_BYTES = 11; /* FLAGS + up to two bytes for heart-rate */
smigielski 61:16f888838853 187 static const unsigned FLAGS_BYTE_INDEX = 0;
smigielski 61:16f888838853 188 static const unsigned WHEEL_REVOLUTIONS_INDEX = 1;
smigielski 61:16f888838853 189 static const unsigned WHEEL_EVENT_INDEX = 5;
smigielski 61:16f888838853 190 static const unsigned CRANK_REVOLUTIONS_INDEX = 1;
smigielski 61:16f888838853 191 static const unsigned CRANK_EVENT_INDEX = 3;
smigielski 61:16f888838853 192
smigielski 61:16f888838853 193
smigielski 61:16f888838853 194 static const unsigned WHEEL_PRESENCE_BITNUM = 0;
smigielski 61:16f888838853 195 static const uint8_t WHEEL_FLAG = (1 << WHEEL_PRESENCE_BITNUM);
balczezzz 62:2ea9997b5249 196 static const unsigned CADENCE_PRESENCE_BITNUM = 1;
smigielski 61:16f888838853 197 static const uint8_t CADENCE_FLAG = (1 << CADENCE_PRESENCE_BITNUM);
smigielski 61:16f888838853 198
smigielski 61:16f888838853 199 //speed
smigielski 61:16f888838853 200 CSCValueBytes(uint32_t wheelRevolutions ,uint16_t wheelEvent) : valueBytes() {
balczezzz 62:2ea9997b5249 201 valueBytes[FLAGS_BYTE_INDEX] = WHEEL_FLAG;
smigielski 61:16f888838853 202 updateWheel(wheelRevolutions,wheelEvent);
smigielski 61:16f888838853 203 }
smigielski 61:16f888838853 204 //cadence
smigielski 61:16f888838853 205 CSCValueBytes(uint16_t crankRevolutions, uint16_t crankEvent ) : valueBytes() {
balczezzz 62:2ea9997b5249 206 valueBytes[FLAGS_BYTE_INDEX] = CADENCE_FLAG;
smigielski 61:16f888838853 207 updateCrank(crankRevolutions,crankEvent);
smigielski 61:16f888838853 208 }
smigielski 61:16f888838853 209
smigielski 61:16f888838853 210 //speed + cadence
smigielski 61:16f888838853 211 CSCValueBytes(uint32_t wheelRevolutions ,uint16_t wheelEvent,uint16_t crankRevolutions, uint16_t crankEvent) : valueBytes() {
balczezzz 62:2ea9997b5249 212 valueBytes[FLAGS_BYTE_INDEX] = (WHEEL_FLAG |CADENCE_FLAG);
smigielski 61:16f888838853 213 updateWheel(wheelRevolutions,wheelEvent);
smigielski 61:16f888838853 214 updateCrank(crankRevolutions,crankEvent);
smigielski 61:16f888838853 215 }
smigielski 61:16f888838853 216
smigielski 61:16f888838853 217
smigielski 61:16f888838853 218 void updateWheel(uint32_t wheelRevolutions ,uint16_t wheelEvent) {
smigielski 61:16f888838853 219
smigielski 61:16f888838853 220 valueBytes[WHEEL_REVOLUTIONS_INDEX] = (uint8_t)(wheelRevolutions & 0xFF);
smigielski 61:16f888838853 221 valueBytes[WHEEL_REVOLUTIONS_INDEX + 1] = (uint8_t)((wheelRevolutions >> 8) & 0xFF);
smigielski 61:16f888838853 222 valueBytes[WHEEL_REVOLUTIONS_INDEX + 2] = (uint8_t)((wheelRevolutions >> 16) & 0xFF);
smigielski 61:16f888838853 223 valueBytes[WHEEL_REVOLUTIONS_INDEX + 3] = (uint8_t)((wheelRevolutions >> 24) & 0xFF);
smigielski 61:16f888838853 224 valueBytes[WHEEL_EVENT_INDEX] = (uint8_t)(wheelEvent & 0xFF);
smigielski 61:16f888838853 225 valueBytes[WHEEL_EVENT_INDEX + 1] = (uint8_t)((wheelEvent >> 8) & 0xFF);
smigielski 61:16f888838853 226 }
smigielski 61:16f888838853 227
smigielski 61:16f888838853 228 void updateCrank(uint16_t crankRevolutions, uint16_t crankEvent) {
smigielski 61:16f888838853 229 int offset = (valueBytes[FLAGS_BYTE_INDEX] & WHEEL_FLAG) ? sizeof(uint32_t)+ sizeof(uint16_t):0;
smigielski 61:16f888838853 230 valueBytes[offset + CRANK_REVOLUTIONS_INDEX] = (uint8_t)(crankRevolutions & 0xFF);
smigielski 61:16f888838853 231 valueBytes[offset + CRANK_REVOLUTIONS_INDEX + 1] = (uint8_t)((crankRevolutions >> 8) & 0xFF);
smigielski 61:16f888838853 232 valueBytes[offset + CRANK_EVENT_INDEX] = (uint8_t)(crankEvent & 0xFF);
smigielski 61:16f888838853 233 valueBytes[offset + CRANK_EVENT_INDEX + 1] = (uint8_t)((crankEvent >> 8) & 0xFF);
smigielski 61:16f888838853 234 }
smigielski 61:16f888838853 235
smigielski 61:16f888838853 236 uint8_t *getPointer(void) {
smigielski 61:16f888838853 237 return valueBytes;
smigielski 61:16f888838853 238 }
smigielski 61:16f888838853 239
smigielski 61:16f888838853 240 const uint8_t *getPointer(void) const {
smigielski 61:16f888838853 241 return valueBytes;
smigielski 61:16f888838853 242 }
smigielski 61:16f888838853 243
smigielski 61:16f888838853 244 unsigned getNumValueBytes(void) const {
smigielski 61:16f888838853 245 return 1 + ((valueBytes[FLAGS_BYTE_INDEX] & WHEEL_FLAG) ? sizeof(uint32_t)+ sizeof(uint16_t):0)
smigielski 61:16f888838853 246 + ((valueBytes[FLAGS_BYTE_INDEX] & CADENCE_FLAG) ? sizeof(uint16_t) + sizeof(uint16_t):0);
smigielski 61:16f888838853 247 }
smigielski 61:16f888838853 248
smigielski 61:16f888838853 249 private:
smigielski 61:16f888838853 250 /* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */
smigielski 61:16f888838853 251 /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */
smigielski 61:16f888838853 252 uint8_t valueBytes[MAX_VALUE_BYTES];
smigielski 61:16f888838853 253 };
smigielski 61:16f888838853 254
smigielski 61:16f888838853 255 private:
smigielski 61:16f888838853 256 BLEDevice &ble;
smigielski 61:16f888838853 257
smigielski 61:16f888838853 258 CSCFeatureBytes feautureBytes;
smigielski 61:16f888838853 259 CSCValueBytes valueBytes;
smigielski 61:16f888838853 260
smigielski 61:16f888838853 261 uint8_t controlPointValue;
smigielski 61:16f888838853 262
smigielski 61:16f888838853 263
smigielski 61:16f888838853 264 GattCharacteristic cscMesurement;
smigielski 61:16f888838853 265 ReadOnlyGattCharacteristic<uint16_t> cscFeatures;
smigielski 61:16f888838853 266 ReadOnlyGattCharacteristic<uint8_t> sensorLocation;
smigielski 61:16f888838853 267 WriteOnlyGattCharacteristic<uint8_t> controlPoint;
smigielski 61:16f888838853 268 };
smigielski 61:16f888838853 269
smigielski 61:16f888838853 270 #endif /* #ifndef __BLE_CYCLE_SPEED_CADENCE_SERVICE_H__*/