BLE demo for the Cycling Power service.
Dependencies: BLE_API mbed nRF51822
CyclingPowerService.h
00001 /* 00002 Copyright (c) 2016 Y. Miyakawa 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 00007 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 00008 subject to the following conditions: 00009 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 00010 00011 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 00012 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 00013 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 00014 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00015 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00016 */ 00017 00018 #ifndef __BLE_CYCLING_POWER_SERVICE_H__ 00019 #define __BLE_CYCLING_POWER_SERVICE_H__ 00020 00021 #include "ble/BLE.h" 00022 00023 #define UUID_CYCLING_POWER_SERVICE 0x1818 00024 #define UUID_SENSOR_LOCATION_CHAR 0x2A5D 00025 #define UUID_CYCLING_POWER_MEASUREMENT_CHAR 0x2A63 00026 #define UUID_CYCLING_POWER_FEATURE_CHAR 0x2A65 00027 #define UUID_CYCLING_POWER_VECTOR_CHAR 0x2A64 00028 #define UUID_CYCLING_POWER_CONTROL_POINT_CHAR 0x2A66 00029 00030 00031 /** 00032 * @class CyclingPowerService 00033 * @brief BLE Service for CyclingPower. <br> 00034 * Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_power.xml <br> 00035 * CyclingPower Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.cycling_power_measurement.xml <br> 00036 * Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.sensor_location.xml 00037 */ 00038 class CyclingPowerService { 00039 public: 00040 enum { 00041 LOCATION_OTHER = 0, 00042 LOCATION_TOP_OF_SHOE, 00043 LOCATION_IN_SHOE, 00044 LOCATION_HIP, 00045 LOCATION_FRONT_WHEEL, 00046 LOCATION_LEFT_CRANK, 00047 LOCATION_RIGHT_CRANK, 00048 LOCATION_LEFT_PEDAL, 00049 LOCATION_RIGHT_PEDAL, 00050 LOCATION_FRONT_HUB, 00051 LOCATION_REAR_DROPOUT, 00052 LOCATION_CHAINSTAY, 00053 LOCATION_REAR_WHEEL, 00054 LOCATION_REAR_HUB, 00055 LOCATION_CHEST, 00056 }; 00057 00058 enum { 00059 FEATURE_PEDAL_POWER_BALANCE = 0x00000001, 00060 FEATURE_ACCUMULATED_TORQUE = 0x00000002, 00061 FEATURE_WHEEL_REVOLUTION_DATA = 0x00000004, 00062 FEATURE_CRANK_REVOLUTION_DATA = 0x00000008, 00063 FEATURE_EXTREME_MAGNITUDES = 0x00000010, 00064 FEATURE_EXTREME_ANGLES = 0x00000020, 00065 FEATURE_TOP_AND_BOTTOM_DEAD_SPOT_ANGLES = 0x00000040, 00066 FEATURE_ACCUMULATED_ENERGY = 0x00000080, 00067 FEATURE_OFFSET_COMPENSATION_INDICATOR = 0x00000100, 00068 FEATURE_OFFSET_COMPENSATION = 0x00000200, 00069 FEATURE_MEASUREMENT_CONTENT_MASKING = 0x00000400, 00070 FEATURE_MULTIPLE_SENSOR_LOCATIONS = 0x00000800, 00071 FEATURE_CRANK_LENGTH_ADJUSTMENT = 0x00001000, 00072 FEATURE_CHAIN_LENGTH_ADJUSTMENT = 0x00002000, 00073 FEATURE_CHAIN_WEIGHT_ADJUSTMENT = 0x00004000, 00074 FEATURE_SPAN_LENGTH_ADJUSTMENT = 0x00008000, 00075 FEATURE_SENSOR_MEASUREMENT_TORQUE_BASED = 0x00010000, 00076 FEATURE_INSTANTANEOUS_MEASUREMENT_DIRECTION = 0x00020000, 00077 FEATURE_FACTORY_CALIBRATION_DATE = 0x00040000, 00078 }; 00079 00080 enum { 00081 FLAG_PEDAL_POWER_BALANCE_PRESENT = 0x0001, 00082 FLAG_PEDAL_POWER_BALANCE_REFERENCE_LEFT = 0x0002, 00083 FLAG_ACCUMULATED_TORQUE_PRESENT = 0x0004, 00084 FLAG_ACCUMULATED_TORQUE_SOURCE_CRANK_BASED = 0x0008, 00085 FLAG_WHEEL_REVOLUTION_DATA_PRESENT = 0x0010, 00086 FLAG_CRANK_REVOLUTION_DATA_PRESENT = 0x0020, 00087 FLAG_EXTREME_FORCE_MAGNITUDES_PRESENT = 0x0040, 00088 FLAG_EXTREME_TORQUE_MAGNITUDES_PRESENT = 0x0080, 00089 FLAG_EXTREME_ANGLES_PRESENT = 0x0100, 00090 FLAG_TOP_DEAD_SPOT_ANGLE_PRESENT = 0x0200, 00091 FLAG_BOTTOM_DEAD_SPOT_ANGLE_PRESENT = 0x0400, 00092 FLAG_ACCUMULATED_ENERGY_PRESENT = 0x0800, 00093 FLAG_OFFSET_COMPENSATION_INDICATOR = 0x1000, 00094 }; 00095 00096 enum { 00097 OPCODE_SET_CUMULATIVE_VALUE = 1, 00098 OPCODE_UPDATE_SENSOR_LOCATION = 2, 00099 OPCODE_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 3, 00100 OPCODE_SET_CRANK_LENGTH = 4, 00101 OPCODE_REQUEST_CRANK_LENGTH = 5, 00102 OPCODE_SET_CHAIN_LENGTH = 6, 00103 OPCODE_REQUEST_CHAIN_LENGTH = 7, 00104 OPCODE_SET_CHAIN_WEIGHT = 8, 00105 OPCODE_REQUEST_CHAIN_WEIGHT = 9, 00106 OPCODE_SET_SPAN_LENGTH = 10, 00107 OPCODE_REQUEST_SPAN_LENGTH = 11, 00108 OPCODE_START_OFFSET_COMPENSATION = 12, 00109 OPCODE_MASK_CYCLING_POWER_MEASUREMENT_CHARACTERISTIC_CONTENT = 13, 00110 OPCODE_REQUEST_SAMPLING_RATE = 14, 00111 OPCODE_REQUEST_FACTORY_CALIBRATION_DATE = 15, 00112 OPCODE_RESPONSE_CODE = 32, 00113 }; 00114 00115 enum { 00116 RESPONSE_SUCCESS = 1, 00117 RESPONSE_OP_CODE_NOT_SUPPORTED, 00118 RESPONSE_INVALID_PARAMETER, 00119 RESPONSE_OPERATION_FAILED, 00120 }; 00121 00122 public: 00123 CyclingPowerService(BLE &_ble, uint32_t feature, uint8_t location) : 00124 ble(_ble), 00125 cyclingPowerMeasurement(UUID_CYCLING_POWER_MEASUREMENT_CHAR, measureData, 00126 MAX_MEASURE_BYTES, MAX_MEASURE_BYTES, 00127 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), 00128 cyclingPowerControlPoint(UUID_CYCLING_POWER_CONTROL_POINT_CHAR, controlData, 00129 MAX_CONTROL_BYTES, MAX_CONTROL_BYTES, 00130 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE), 00131 cyclingPowerFeature(UUID_CYCLING_POWER_FEATURE_CHAR, &feature), 00132 cyclingPowerLocation(UUID_SENSOR_LOCATION_CHAR, &location) { 00133 setupService(); 00134 } 00135 00136 void updateCyclingPower(uint16_t flags, int16_t pwr, uint8_t bal, int16_t maxTorque, int16_t minTorque, uint16_t dnw, uint16_t dtw, uint16_t dnc, uint16_t dtc) { 00137 instantaneousPower = pwr; 00138 pedalPowerBalance = bal; 00139 maximumTorqueMagnitude = maxTorque; 00140 minimumTorqueMagnitude = minTorque; 00141 00142 cumulativeWheelRev += dnw; 00143 lastWheelEventTime += dtw; 00144 cumulativeCrankRev += dnc; 00145 lastCrankEventTime += dtc; 00146 00147 unsigned i = 0; 00148 measureData[i++] = (uint8_t)(flags & 0xFF); 00149 measureData[i++] = (uint8_t)(flags >> 8); 00150 00151 measureData[i++] = (uint8_t)(instantaneousPower & 0xFF); 00152 measureData[i++] = (uint8_t)(instantaneousPower >> 8); 00153 00154 if (flags & FLAG_PEDAL_POWER_BALANCE_PRESENT) { 00155 measureData[i++] = pedalPowerBalance; 00156 } 00157 if (flags & FLAG_WHEEL_REVOLUTION_DATA_PRESENT) { 00158 measureData[i++] = (uint8_t)(cumulativeWheelRev & 0xFF); 00159 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 8) & 0xFF); 00160 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 16) & 0xFF); 00161 measureData[i++] = (uint8_t)((cumulativeWheelRev >> 24) & 0xFF); 00162 00163 measureData[i++] = (uint8_t)(lastWheelEventTime & 0xFF); 00164 measureData[i++] = (uint8_t)(lastWheelEventTime >> 8); 00165 } 00166 if (flags & FLAG_CRANK_REVOLUTION_DATA_PRESENT) { 00167 measureData[i++] = (uint8_t)(cumulativeCrankRev & 0xFF); 00168 measureData[i++] = (uint8_t)(cumulativeCrankRev >> 8); 00169 00170 measureData[i++] = (uint8_t)(lastCrankEventTime & 0xFF); 00171 measureData[i++] = (uint8_t)(lastCrankEventTime >> 8); 00172 } 00173 if (flags & FLAG_EXTREME_TORQUE_MAGNITUDES_PRESENT) { 00174 measureData[i++] = (uint8_t)(maximumTorqueMagnitude & 0xFF); 00175 measureData[i++] = (uint8_t)(maximumTorqueMagnitude >> 8); 00176 00177 measureData[i++] = (uint8_t)(minimumTorqueMagnitude & 0xFF); 00178 measureData[i++] = (uint8_t)(minimumTorqueMagnitude >> 8); 00179 } 00180 unsigned nbyte = i; 00181 ble.updateCharacteristicValue(cyclingPowerMeasurement.getValueAttribute().getHandle(), measureData, nbyte); 00182 } 00183 00184 void indicateResponse(uint8_t opCode, uint8_t responseValue) { 00185 controlData[0] = 0x20; // Response Code 00186 controlData[1] = opCode; 00187 controlData[2] = responseValue; 00188 unsigned nbyte = 3; 00189 ble.updateCharacteristicValue(cyclingPowerControlPoint.getValueAttribute().getHandle(), controlData, nbyte); 00190 } 00191 00192 void indicateResponse(uint8_t opCode, uint8_t responseValue, uint16_t responseParameter) { 00193 controlData[0] = 0x20; // Response Code 00194 controlData[1] = opCode; 00195 controlData[2] = responseValue; 00196 controlData[3] = (uint8_t)(responseParameter & 0xFF); 00197 controlData[4] = (uint8_t)(responseParameter >> 8); 00198 unsigned nbyte = 5; 00199 ble.updateCharacteristicValue(cyclingPowerControlPoint.getValueAttribute().getHandle(), controlData, nbyte); 00200 } 00201 00202 virtual void onDataWritten(const GattWriteCallbackParams *params) { 00203 if (params->handle == cyclingPowerControlPoint.getValueAttribute().getHandle()) { 00204 uint32_t uu; 00205 uint8_t opCode = params->data[0]; 00206 switch(opCode) { 00207 case OPCODE_SET_CUMULATIVE_VALUE: 00208 uu = params->data[4]; 00209 uu *= 256; 00210 uu += params->data[3]; 00211 uu *= 256; 00212 uu += params->data[2]; 00213 uu *= 256; 00214 uu += params->data[1]; 00215 cumulativeWheelRev = uu; 00216 indicateResponse(opCode, CyclingPowerService::RESPONSE_SUCCESS); 00217 break; 00218 default: 00219 indicateResponse(opCode, CyclingPowerService::RESPONSE_OP_CODE_NOT_SUPPORTED); 00220 } 00221 } 00222 } 00223 00224 protected: 00225 void setupService(void) { 00226 instantaneousPower = 0; 00227 pedalPowerBalance = 50 * 2; // 50% 00228 maximumTorqueMagnitude = 0; 00229 minimumTorqueMagnitude = 0; 00230 00231 cumulativeWheelRev = 0; 00232 lastWheelEventTime = 0; 00233 cumulativeCrankRev = 0; 00234 lastCrankEventTime = 0; 00235 00236 GattCharacteristic *charTable[] = {&cyclingPowerMeasurement, &cyclingPowerFeature, &cyclingPowerLocation, &cyclingPowerControlPoint}; 00237 GattService cyclingPowerService(UUID_CYCLING_POWER_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); 00238 00239 ble.addService(cyclingPowerService); 00240 ble.onDataWritten(this, &CyclingPowerService::onDataWritten); 00241 } 00242 00243 protected: 00244 BLE &ble; 00245 00246 GattCharacteristic cyclingPowerMeasurement; 00247 GattCharacteristic cyclingPowerControlPoint; 00248 ReadOnlyGattCharacteristic<uint32_t> cyclingPowerFeature; 00249 ReadOnlyGattCharacteristic<uint8_t> cyclingPowerLocation; 00250 00251 static const unsigned MAX_MEASURE_BYTES = 19; 00252 static const unsigned MAX_CONTROL_BYTES = 5; 00253 00254 uint8_t measureData[MAX_MEASURE_BYTES]; 00255 uint8_t controlData[MAX_CONTROL_BYTES]; 00256 00257 int16_t instantaneousPower; 00258 uint8_t pedalPowerBalance; 00259 int16_t maximumTorqueMagnitude; 00260 int16_t minimumTorqueMagnitude; 00261 00262 uint32_t cumulativeWheelRev; 00263 uint16_t lastWheelEventTime; 00264 uint16_t cumulativeCrankRev; 00265 uint16_t lastCrankEventTime; 00266 }; 00267 00268 #endif /* #ifndef __BLE_CYCLING_POWER_SERVICE_H__*/
Generated on Sat Jul 16 2022 16:26:37 by 1.7.2