BLE demo for the Cycling Speed and Cadence service.
Dependencies: BLE_API mbed nRF51822
Diff: CyclingSpeedAndCadenceService.h
- Revision:
- 0:ea0fa3076efd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CyclingSpeedAndCadenceService.h Thu Mar 10 13:09:47 2016 +0000 @@ -0,0 +1,196 @@ +/* +Copyright (c) 2016 Y. Miyakawa + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software +and associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__ +#define __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__ + +#include "ble/BLE.h" + +#define UUID_SENSOR_LOCATION_CHAR 0x2A5D +#define UUID_CSC_CONTROL_POINT_CHAR 0x2A55 + + +/** +* @class CyclingSpeedAndCadenceService +* @brief BLE Service for Cycling Speed and Cadence. <br> +* Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.cycling_speed_and_cadence.xml <br> +* CyclingSpeedAndCadenceService Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.csc_measurement.xml <br> +* Location: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.sensor_location.xml +*/ +class CyclingSpeedAndCadenceService { +public: + enum { + LOCATION_OTHER = 0, + LOCATION_TOP_OF_SHOE, + LOCATION_IN_SHOE, + LOCATION_HIP, + LOCATION_FRONT_WHEEL, + LOCATION_LEFT_CRANK, + LOCATION_RIGHT_CRANK, + LOCATION_LEFT_PEDAL, + LOCATION_RIGHT_PEDAL, + LOCATION_FRONT_HUB, + LOCATION_REAR_DROPOUT, + LOCATION_CHAINSTAY, + LOCATION_REAR_WHEEL, + LOCATION_REAR_HUB, + LOCATION_CHEST, + }; + + enum { + FEATURE_WHEEL_REVOLUTION_DATA = 0x0001, + FEATURE_CRANK_REVOLUTION_DATA = 0x0002, + FEATURE_MULTIPLE_SENSOR_LOCATIONS = 0x0004, + }; + + enum { + FLAG_WHEEL_REVOLUTION_DATA_PRESENT = 0x01, + FLAG_CRANK_REVOLUTION_DATA_PRESENT = 0x02, + }; + + enum { + OPCODE_SET_CUMULATIVE_VALUE = 1, + OPCODE_START_SENSOR_CALIBRATION = 2, + OPCODE_UPDATE_SENSOR_LOCATION = 3, + OPCODE_REQUEST_SUPPORTED_SENSOR_LOCATIONS = 4, + OPCODE_RESPONSE_CODE = 16, + }; + + enum { + RESPONSE_SUCCESS = 1, + RESPONSE_OP_CODE_NOT_SUPPORTED = 2, + RESPONSE_INVALID_PARAMETER = 3, + RESPONSE_OPERATION_FAILED = 4, + }; + +public: + CyclingSpeedAndCadenceService(BLE &_ble, uint16_t feature, uint8_t location) : + ble(_ble), + cyclingSpeedAndCadenceMeasurement(GattCharacteristic::UUID_CSC_MEASUREMENT_CHAR, measureData, + MAX_MEASURE_BYTES, MAX_MEASURE_BYTES, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY), + cyclingSpeedAndCadenceControlPoint(UUID_CSC_CONTROL_POINT_CHAR, controlData, + MAX_CONTROL_BYTES, MAX_CONTROL_BYTES, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE), + cyclingSpeedAndCadenceFeature(GattCharacteristic::UUID_CSC_FEATURE_CHAR, &feature), + cyclingSpeedAndCadenceLocation(UUID_SENSOR_LOCATION_CHAR, &location) { + setupService(); + } + + void updateCyclingSpeedAndCadence(uint8_t flags, uint16_t dnw, uint16_t dtw, uint16_t dnc, uint16_t dtc) { + cumulativeWheelRev += dnw; + lastWheelEventTime += dtw; + cumulativeCrankRev += dnc; + lastCrankEventTime += dtc; + + unsigned i = 0; + measureData[i++] = flags; + + if (flags & FLAG_WHEEL_REVOLUTION_DATA_PRESENT) { + measureData[i++] = (uint8_t)(cumulativeWheelRev & 0xFF); + measureData[i++] = (uint8_t)((cumulativeWheelRev >> 8) & 0xFF); + measureData[i++] = (uint8_t)((cumulativeWheelRev >> 16) & 0xFF); + measureData[i++] = (uint8_t)((cumulativeWheelRev >> 24) & 0xFF); + + measureData[i++] = (uint8_t)(lastWheelEventTime & 0xFF); + measureData[i++] = (uint8_t)(lastWheelEventTime >> 8); + } + if (flags & FLAG_CRANK_REVOLUTION_DATA_PRESENT) { + measureData[i++] = (uint8_t)(cumulativeCrankRev & 0xFF); + measureData[i++] = (uint8_t)(cumulativeCrankRev >> 8); + + measureData[i++] = (uint8_t)(lastCrankEventTime & 0xFF); + measureData[i++] = (uint8_t)(lastCrankEventTime >> 8); + } + unsigned nbyte = i; + ble.updateCharacteristicValue(cyclingSpeedAndCadenceMeasurement.getValueAttribute().getHandle(), measureData, nbyte); + } + + void indicateResponse(uint8_t opCode, uint8_t responseValue) { + controlData[0] = OPCODE_RESPONSE_CODE; + controlData[1] = opCode; + controlData[2] = responseValue; + unsigned nbyte = 3; + ble.updateCharacteristicValue(cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle(), controlData, nbyte); + } + + void indicateResponse(uint8_t opCode, uint8_t responseValue, uint8_t responseParameter) { + controlData[0] = OPCODE_RESPONSE_CODE; + controlData[1] = opCode; + controlData[2] = responseValue; + controlData[3] = responseParameter; + unsigned nbyte = 4; + ble.updateCharacteristicValue(cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle(), controlData, nbyte); + } + + virtual void onDataWritten(const GattWriteCallbackParams *params) { + if (params->handle == cyclingSpeedAndCadenceControlPoint.getValueAttribute().getHandle()) { + uint32_t uu; + uint8_t opCode = params->data[0]; + switch(opCode) { + case OPCODE_SET_CUMULATIVE_VALUE: + uu = params->data[4]; + uu *= 256; + uu += params->data[3]; + uu *= 256; + uu += params->data[2]; + uu *= 256; + uu += params->data[1]; + cumulativeWheelRev = uu; + indicateResponse(opCode, CyclingSpeedAndCadenceService::RESPONSE_SUCCESS); + break; + default: + indicateResponse(opCode, CyclingSpeedAndCadenceService::RESPONSE_OP_CODE_NOT_SUPPORTED); + } + } + } + +protected: + void setupService(void) { + cumulativeWheelRev = 0; + lastWheelEventTime = 0; + cumulativeCrankRev = 0; + lastCrankEventTime = 0; + + GattCharacteristic *charTable[] = {&cyclingSpeedAndCadenceMeasurement, &cyclingSpeedAndCadenceFeature, &cyclingSpeedAndCadenceLocation, &cyclingSpeedAndCadenceControlPoint}; + GattService cyclingSpeedAndCadenceService(GattService::UUID_CYCLING_SPEED_AND_CADENCE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); + + ble.addService(cyclingSpeedAndCadenceService); + ble.onDataWritten(this, &CyclingSpeedAndCadenceService::onDataWritten); + } + +protected: + BLE &ble; + + GattCharacteristic cyclingSpeedAndCadenceMeasurement; + GattCharacteristic cyclingSpeedAndCadenceControlPoint; + ReadOnlyGattCharacteristic<uint16_t> cyclingSpeedAndCadenceFeature; + ReadOnlyGattCharacteristic<uint8_t> cyclingSpeedAndCadenceLocation; + + static const unsigned MAX_MEASURE_BYTES = 11; + static const unsigned MAX_CONTROL_BYTES = 4; + + uint8_t measureData[MAX_MEASURE_BYTES]; + uint8_t controlData[MAX_CONTROL_BYTES]; + + uint32_t cumulativeWheelRev; + uint16_t lastWheelEventTime; + uint16_t cumulativeCrankRev; + uint16_t lastCrankEventTime; +}; + +#endif /* #ifndef __BLE_CYCLING_SPEED_AND_CADENCE_SERVICE_H__*/