BLE demo for the Cycling Speed and Cadence service.

Dependencies:   BLE_API mbed nRF51822

Committer:
p3miya
Date:
Thu Mar 10 13:09:47 2016 +0000
Revision:
0:ea0fa3076efd
BLE demo for the Cycling Speed and Cadence service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
p3miya 0:ea0fa3076efd 1 /*
p3miya 0:ea0fa3076efd 2 Copyright (c) 2016 Y. Miyakawa
p3miya 0:ea0fa3076efd 3
p3miya 0:ea0fa3076efd 4 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
p3miya 0:ea0fa3076efd 5 and associated documentation files (the "Software"), to deal in the Software without restriction,
p3miya 0:ea0fa3076efd 6 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
p3miya 0:ea0fa3076efd 7 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
p3miya 0:ea0fa3076efd 8 subject to the following conditions:
p3miya 0:ea0fa3076efd 9 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
p3miya 0:ea0fa3076efd 10
p3miya 0:ea0fa3076efd 11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
p3miya 0:ea0fa3076efd 12 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
p3miya 0:ea0fa3076efd 13 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
p3miya 0:ea0fa3076efd 14 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
p3miya 0:ea0fa3076efd 15 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
p3miya 0:ea0fa3076efd 16 */
p3miya 0:ea0fa3076efd 17
p3miya 0:ea0fa3076efd 18 #ifndef __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__
p3miya 0:ea0fa3076efd 19 #define __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__
p3miya 0:ea0fa3076efd 20
p3miya 0:ea0fa3076efd 21 #include "ble/BLE.h"
p3miya 0:ea0fa3076efd 22
p3miya 0:ea0fa3076efd 23 #define UUID_SENSOR_LOCATION_CHAR 0x2A5D
p3miya 0:ea0fa3076efd 24 #define UUID_CSC_CONTROL_POINT_CHAR 0x2A55
p3miya 0:ea0fa3076efd 25
p3miya 0:ea0fa3076efd 26
p3miya 0:ea0fa3076efd 27 /**
p3miya 0:ea0fa3076efd 28 * @class CyclingSpeedAndCadenceService
p3miya 0:ea0fa3076efd 29 * @brief BLE Service for Cycling Speed and Cadence. <br>
p3miya 0:ea0fa3076efd 30 * Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_speed_and_cadence.xml <br>
p3miya 0:ea0fa3076efd 31 * CyclingSpeedAndCadenceService Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.csc_measurement.xml <br>
p3miya 0:ea0fa3076efd 32 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.sensor_location.xml
p3miya 0:ea0fa3076efd 33 */
p3miya 0:ea0fa3076efd 34 class CyclingSpeedAndCadenceService {
p3miya 0:ea0fa3076efd 35 public:
p3miya 0:ea0fa3076efd 36 enum {
p3miya 0:ea0fa3076efd 37 LOCATION_OTHER = 0,
p3miya 0:ea0fa3076efd 38 LOCATION_TOP_OF_SHOE,
p3miya 0:ea0fa3076efd 39 LOCATION_IN_SHOE,
p3miya 0:ea0fa3076efd 40 LOCATION_HIP,
p3miya 0:ea0fa3076efd 41 LOCATION_FRONT_WHEEL,
p3miya 0:ea0fa3076efd 42 LOCATION_LEFT_CRANK,
p3miya 0:ea0fa3076efd 43 LOCATION_RIGHT_CRANK,
p3miya 0:ea0fa3076efd 44 LOCATION_LEFT_PEDAL,
p3miya 0:ea0fa3076efd 45 LOCATION_RIGHT_PEDAL,
p3miya 0:ea0fa3076efd 46 LOCATION_FRONT_HUB,
p3miya 0:ea0fa3076efd 47 LOCATION_REAR_DROPOUT,
p3miya 0:ea0fa3076efd 48 LOCATION_CHAINSTAY,
p3miya 0:ea0fa3076efd 49 LOCATION_REAR_WHEEL,
p3miya 0:ea0fa3076efd 50 LOCATION_REAR_HUB,
p3miya 0:ea0fa3076efd 51 LOCATION_CHEST,
p3miya 0:ea0fa3076efd 52 };
p3miya 0:ea0fa3076efd 53
p3miya 0:ea0fa3076efd 54 enum {
p3miya 0:ea0fa3076efd 55 FEATURE_WHEEL_REVOLUTION_DATA = 0x0001,
p3miya 0:ea0fa3076efd 56 FEATURE_CRANK_REVOLUTION_DATA = 0x0002,
p3miya 0:ea0fa3076efd 57 FEATURE_MULTIPLE_SENSOR_LOCATIONS = 0x0004,
p3miya 0:ea0fa3076efd 58 };
p3miya 0:ea0fa3076efd 59
p3miya 0:ea0fa3076efd 60 enum {
p3miya 0:ea0fa3076efd 61 FLAG_WHEEL_REVOLUTION_DATA_PRESENT = 0x01,
p3miya 0:ea0fa3076efd 62 FLAG_CRANK_REVOLUTION_DATA_PRESENT = 0x02,
p3miya 0:ea0fa3076efd 63 };
p3miya 0:ea0fa3076efd 64
p3miya 0:ea0fa3076efd 65 enum {
p3miya 0:ea0fa3076efd 66 OPCODE_SET_CUMULATIVE_VALUE = 1,
p3miya 0:ea0fa3076efd 67 OPCODE_START_SENSOR_CALIBRATION = 2,
p3miya 0:ea0fa3076efd 68 OPCODE_UPDATE_SENSOR_LOCATION = 3,
p3miya 0:ea0fa3076efd 69 OPCODE_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 4,
p3miya 0:ea0fa3076efd 70 OPCODE_RESPONSE_CODE = 16,
p3miya 0:ea0fa3076efd 71 };
p3miya 0:ea0fa3076efd 72
p3miya 0:ea0fa3076efd 73 enum {
p3miya 0:ea0fa3076efd 74 RESPONSE_SUCCESS = 1,
p3miya 0:ea0fa3076efd 75 RESPONSE_OP_CODE_NOT_SUPPORTED = 2,
p3miya 0:ea0fa3076efd 76 RESPONSE_INVALID_PARAMETER = 3,
p3miya 0:ea0fa3076efd 77 RESPONSE_OPERATION_FAILED = 4,
p3miya 0:ea0fa3076efd 78 };
p3miya 0:ea0fa3076efd 79
p3miya 0:ea0fa3076efd 80 public:
p3miya 0:ea0fa3076efd 81 CyclingSpeedAndCadenceService(BLE &_ble, uint16_t feature, uint8_t location) :
p3miya 0:ea0fa3076efd 82 ble(_ble),
p3miya 0:ea0fa3076efd 83 cyclingSpeedAndCadenceMeasurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, measureData,
p3miya 0:ea0fa3076efd 84 MAX_MEASURE_BYTES, MAX_MEASURE_BYTES,
p3miya 0:ea0fa3076efd 85 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
p3miya 0:ea0fa3076efd 86 cyclingSpeedAndCadenceControlPoint(UUID_CSC_CONTROL_POINT_CHAR, controlData,
p3miya 0:ea0fa3076efd 87 MAX_CONTROL_BYTES, MAX_CONTROL_BYTES,
p3miya 0:ea0fa3076efd 88 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE),
p3miya 0:ea0fa3076efd 89 cyclingSpeedAndCadenceFeature(GattCharacteristic::UUID_CSC_FEATURE_CHAR, &feature),
p3miya 0:ea0fa3076efd 90 cyclingSpeedAndCadenceLocation(UUID_SENSOR_LOCATION_CHAR, &location) {
p3miya 0:ea0fa3076efd 91 setupService();
p3miya 0:ea0fa3076efd 92 }
p3miya 0:ea0fa3076efd 93
p3miya 0:ea0fa3076efd 94 void updateCyclingSpeedAndCadence(uint8_t flags, uint16_t dnw, uint16_t dtw, uint16_t dnc, uint16_t dtc) {
p3miya 0:ea0fa3076efd 95 cumulativeWheelRev += dnw;
p3miya 0:ea0fa3076efd 96 lastWheelEventTime += dtw;
p3miya 0:ea0fa3076efd 97 cumulativeCrankRev += dnc;
p3miya 0:ea0fa3076efd 98 lastCrankEventTime += dtc;
p3miya 0:ea0fa3076efd 99
p3miya 0:ea0fa3076efd 100 unsigned i = 0;
p3miya 0:ea0fa3076efd 101 measureData[i++] = flags;
p3miya 0:ea0fa3076efd 102
p3miya 0:ea0fa3076efd 103 if (flags & FLAG_WHEEL_REVOLUTION_DATA_PRESENT) {
p3miya 0:ea0fa3076efd 104 measureData[i++] = (uint8_t)(cumulativeWheelRev & 0xFF);
p3miya 0:ea0fa3076efd 105 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 8) & 0xFF);
p3miya 0:ea0fa3076efd 106 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 16) & 0xFF);
p3miya 0:ea0fa3076efd 107 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 24) & 0xFF);
p3miya 0:ea0fa3076efd 108
p3miya 0:ea0fa3076efd 109 measureData[i++] = (uint8_t)(lastWheelEventTime & 0xFF);
p3miya 0:ea0fa3076efd 110 measureData[i++] = (uint8_t)(lastWheelEventTime >> 8);
p3miya 0:ea0fa3076efd 111 }
p3miya 0:ea0fa3076efd 112 if (flags & FLAG_CRANK_REVOLUTION_DATA_PRESENT) {
p3miya 0:ea0fa3076efd 113 measureData[i++] = (uint8_t)(cumulativeCrankRev & 0xFF);
p3miya 0:ea0fa3076efd 114 measureData[i++] = (uint8_t)(cumulativeCrankRev >> 8);
p3miya 0:ea0fa3076efd 115
p3miya 0:ea0fa3076efd 116 measureData[i++] = (uint8_t)(lastCrankEventTime & 0xFF);
p3miya 0:ea0fa3076efd 117 measureData[i++] = (uint8_t)(lastCrankEventTime >> 8);
p3miya 0:ea0fa3076efd 118 }
p3miya 0:ea0fa3076efd 119 unsigned nbyte = i;
p3miya 0:ea0fa3076efd 120 ble.updateCharacteristicValue(cyclingSpeedAndCadenceMeasurement.getValueAttribute().getHandle(), measureData, nbyte);
p3miya 0:ea0fa3076efd 121 }
p3miya 0:ea0fa3076efd 122
p3miya 0:ea0fa3076efd 123 void indicateResponse(uint8_t opCode, uint8_t responseValue) {
p3miya 0:ea0fa3076efd 124 controlData[0] = OPCODE_RESPONSE_CODE;
p3miya 0:ea0fa3076efd 125 controlData[1] = opCode;
p3miya 0:ea0fa3076efd 126 controlData[2] = responseValue;
p3miya 0:ea0fa3076efd 127 unsigned nbyte = 3;
p3miya 0:ea0fa3076efd 128 ble.updateCharacteristicValue(cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle(), controlData, nbyte);
p3miya 0:ea0fa3076efd 129 }
p3miya 0:ea0fa3076efd 130
p3miya 0:ea0fa3076efd 131 void indicateResponse(uint8_t opCode, uint8_t responseValue, uint8_t responseParameter) {
p3miya 0:ea0fa3076efd 132 controlData[0] = OPCODE_RESPONSE_CODE;
p3miya 0:ea0fa3076efd 133 controlData[1] = opCode;
p3miya 0:ea0fa3076efd 134 controlData[2] = responseValue;
p3miya 0:ea0fa3076efd 135 controlData[3] = responseParameter;
p3miya 0:ea0fa3076efd 136 unsigned nbyte = 4;
p3miya 0:ea0fa3076efd 137 ble.updateCharacteristicValue(cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle(), controlData, nbyte);
p3miya 0:ea0fa3076efd 138 }
p3miya 0:ea0fa3076efd 139
p3miya 0:ea0fa3076efd 140 virtual void onDataWritten(const GattWriteCallbackParams *params) {
p3miya 0:ea0fa3076efd 141 if (params->handle == cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle()) {
p3miya 0:ea0fa3076efd 142 uint32_t uu;
p3miya 0:ea0fa3076efd 143 uint8_t opCode = params->data[0];
p3miya 0:ea0fa3076efd 144 switch(opCode) {
p3miya 0:ea0fa3076efd 145 case OPCODE_SET_CUMULATIVE_VALUE:
p3miya 0:ea0fa3076efd 146 uu = params->data[4];
p3miya 0:ea0fa3076efd 147 uu *= 256;
p3miya 0:ea0fa3076efd 148 uu += params->data[3];
p3miya 0:ea0fa3076efd 149 uu *= 256;
p3miya 0:ea0fa3076efd 150 uu += params->data[2];
p3miya 0:ea0fa3076efd 151 uu *= 256;
p3miya 0:ea0fa3076efd 152 uu += params->data[1];
p3miya 0:ea0fa3076efd 153 cumulativeWheelRev = uu;
p3miya 0:ea0fa3076efd 154 indicateResponse(opCode, CyclingSpeedAndCadenceService::RESPONSE_SUCCESS);
p3miya 0:ea0fa3076efd 155 break;
p3miya 0:ea0fa3076efd 156 default:
p3miya 0:ea0fa3076efd 157 indicateResponse(opCode, CyclingSpeedAndCadenceService::RESPONSE_OP_CODE_NOT_SUPPORTED);
p3miya 0:ea0fa3076efd 158 }
p3miya 0:ea0fa3076efd 159 }
p3miya 0:ea0fa3076efd 160 }
p3miya 0:ea0fa3076efd 161
p3miya 0:ea0fa3076efd 162 protected:
p3miya 0:ea0fa3076efd 163 void setupService(void) {
p3miya 0:ea0fa3076efd 164 cumulativeWheelRev = 0;
p3miya 0:ea0fa3076efd 165 lastWheelEventTime = 0;
p3miya 0:ea0fa3076efd 166 cumulativeCrankRev = 0;
p3miya 0:ea0fa3076efd 167 lastCrankEventTime = 0;
p3miya 0:ea0fa3076efd 168
p3miya 0:ea0fa3076efd 169 GattCharacteristic *charTable[] = {&cyclingSpeedAndCadenceMeasurement, &cyclingSpeedAndCadenceFeature, &cyclingSpeedAndCadenceLocation, &cyclingSpeedAndCadenceControlPoint};
p3miya 0:ea0fa3076efd 170 GattService cyclingSpeedAndCadenceService(GattService::UUID_CYCLING_SPEED_AND_CADENCE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
p3miya 0:ea0fa3076efd 171
p3miya 0:ea0fa3076efd 172 ble.addService(cyclingSpeedAndCadenceService);
p3miya 0:ea0fa3076efd 173 ble.onDataWritten(this, &CyclingSpeedAndCadenceService::onDataWritten);
p3miya 0:ea0fa3076efd 174 }
p3miya 0:ea0fa3076efd 175
p3miya 0:ea0fa3076efd 176 protected:
p3miya 0:ea0fa3076efd 177 BLE &ble;
p3miya 0:ea0fa3076efd 178
p3miya 0:ea0fa3076efd 179 GattCharacteristic cyclingSpeedAndCadenceMeasurement;
p3miya 0:ea0fa3076efd 180 GattCharacteristic cyclingSpeedAndCadenceControlPoint;
p3miya 0:ea0fa3076efd 181 ReadOnlyGattCharacteristic<uint16_t> cyclingSpeedAndCadenceFeature;
p3miya 0:ea0fa3076efd 182 ReadOnlyGattCharacteristic<uint8_t> cyclingSpeedAndCadenceLocation;
p3miya 0:ea0fa3076efd 183
p3miya 0:ea0fa3076efd 184 static const unsigned MAX_MEASURE_BYTES = 11;
p3miya 0:ea0fa3076efd 185 static const unsigned MAX_CONTROL_BYTES = 4;
p3miya 0:ea0fa3076efd 186
p3miya 0:ea0fa3076efd 187 uint8_t measureData[MAX_MEASURE_BYTES];
p3miya 0:ea0fa3076efd 188 uint8_t controlData[MAX_CONTROL_BYTES];
p3miya 0:ea0fa3076efd 189
p3miya 0:ea0fa3076efd 190 uint32_t cumulativeWheelRev;
p3miya 0:ea0fa3076efd 191 uint16_t lastWheelEventTime;
p3miya 0:ea0fa3076efd 192 uint16_t cumulativeCrankRev;
p3miya 0:ea0fa3076efd 193 uint16_t lastCrankEventTime;
p3miya 0:ea0fa3076efd 194 };
p3miya 0:ea0fa3076efd 195
p3miya 0:ea0fa3076efd 196 #endif /* #ifndef __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__*/