BLE demo for the Cycling Speed and Cadence service.
Dependencies: BLE_API mbed nRF51822
CyclingSpeedAndCadenceService.h@0:ea0fa3076efd, 2016-03-10 (annotated)
- 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?
User | Revision | Line number | New 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__*/ |