BLE demo for the Cycling Speed and Cadence service.

Dependencies:   BLE_API mbed nRF51822

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__*/