BLE GATT-service implementation for high quantity sensor data from a MPU6050-accelerator/gyroscope

Dependencies:   BLE_API mbed nRF51822 MPU6050_lib

Revision:
3:d72d9195dc26
Child:
4:a97e6917f731
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPU6050Service.h	Thu Jun 25 14:35:26 2015 +0000
@@ -0,0 +1,159 @@
+#pragma once
+#ifndef __MPU6050_SERVICE_H__
+#define __MPU6050_SERVICE_H__
+
+#include "BLE.h"
+
+typedef struct
+{
+    uint16_t    a1, a2, a3;
+    uint16_t    temp;
+    uint16_t    g1, g2, g3;
+} mpu6050SensorReading_t;
+
+typedef struct
+{
+    mpu6050SensorReading_t  data;
+    uint64_t                clock_us;
+} mpu6050SensorData_t;
+
+typedef enum
+{
+    ACCEL_RANGE_2G  = 0x00, // 0b__00
+    ACCEL_RANGE_4G  = 0x01, // 0b__01
+    ACCEL_RANGE_8G  = 0x02, // 0b__10
+    ACCEL_RANGE_16G = 0x03, // 0b__11
+    
+    GYRO_RANGE_250  = 0x00, // 0b00__
+    GYRO_RANGE_500  = 0x04, // 0b01__
+    GYRO_RANGE_1000 = 0x08, // 0b10__
+    GYRO_RANGE_2000 = 0x0C  // 0b11__
+} mpu6050MeasuringRange_t;
+
+inline mpu6050MeasuringRange_t operator|(mpu6050MeasuringRange_t a, mpu6050MeasuringRange_t b) { return static_cast<mpu6050MeasuringRange_t>(static_cast<int>(a) | static_cast<int>(b)); }
+
+class MPU6050Service
+{
+    public:        
+        enum
+        {
+            UUID_MP6050_SERVICE                 = 0xA123,
+            
+            UUID_MPU6050_SENSOR_DATA_CHAR       = 0xA124,
+            UUID_MPU6050_MEASURING_RANGE_CHAR   = 0xA125,
+            UUID_MPU6050_MASTER_CLOCK_CHAR      = 0xA126
+        };
+        
+        MPU6050Service
+        (
+            BLE                            &ble, 
+            const mpu6050SensorData_t      *initialData         = NULL, 
+            const mpu6050MeasuringRange_t   measuringRange      = ACCEL_RANGE_2G | GYRO_RANGE_250, 
+            const uint64_t                  masterClock_us      = 0
+        ) :
+            gattServer(ble.gattServer()),
+            sensorDataCharacteristic
+            (
+                UUID_MPU6050_SENSOR_DATA_CHAR,
+                (mpu6050SensorData_t*)initialData,
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY // improving latency by repurposing notifications and "writing" the client
+                                                                    // (i.e. indicating the client but not wait for a response)
+            ),
+            measuringRangeCharacteristic
+            (
+                UUID_MPU6050_MEASURING_RANGE_CHAR,
+                (mpu6050MeasuringRange_t*)&measuringRange,
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE // also improving latency 
+            ),
+            masterClockCharacteristic
+            (
+                UUID_MPU6050_MASTER_CLOCK_CHAR,
+                (uint64_t*)&masterClock_us,
+                GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE // look above again
+            )
+        {
+            static bool serviceAdded = false; // MOS is a one-timer
+            if (serviceAdded)
+                return;
+                
+            GattCharacteristic *charTable[] =
+            {
+                &sensorDataCharacteristic,
+                &measuringRangeCharacteristic,
+                &masterClockCharacteristic
+            };
+            
+            GattService mpu6050Service(UUID_MP6050_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic*));
+            
+            gattServer.addService(mpu6050Service);
+            gattServer.onDataSent(this, &MPU6050Service::dataSentCallback);
+            gattServer.onDataWritten(this, &MPU6050Service::dataWrittenCallback);
+            
+            serviceAdded = true;
+        }
+        
+        void start()
+        {
+            // sending data once will invoke the dataSent(...) callback later on
+            // which will be looped by the event driven behavior of the BLE API (because it will send data again on it's own)
+            updateSensorDataCharacteristic();
+        }
+        
+    private:
+        GattServer                                             &gattServer; 
+        ReadOnlyGattCharacteristic<mpu6050SensorData_t>         sensorDataCharacteristic;
+        WriteOnlyGattCharacteristic<mpu6050MeasuringRange_t>    measuringRangeCharacteristic;
+        WriteOnlyGattCharacteristic<uint64_t>                   masterClockCharacteristic;
+        
+        union
+        {
+            struct
+            {
+                uint8_t accel_x_h,  accel_x_l;
+                uint8_t accel_y_h,  accel_y_l;
+                uint8_t accel_z_h,  accel_z_l;
+                
+                uint8_t temp_h,     temp_l;
+                
+                uint8_t gyro_x_h,   gyro_x_l;
+                uint8_t gyro_y_h,   gyro_y_l;
+                uint8_t gyro_z_h,   gyro_z_l;
+            } registers;
+            
+            mpu6050SensorReading_t data;
+        } converter;
+        
+        void dataSentCallback(unsigned count)
+        {
+            // we came here, if we just sent data, 
+            // so lets keep the BLE stack busy by sending data again
+            updateSensorDataCharacteristic();
+        }
+        
+        void dataWrittenCallback(const GattWriteCallbackParams *context)
+        {
+            // some writable characteristics were updated by the client
+        }
+        
+        void updateSensorDataCharacteristic()
+        {         
+            mpu6050SensorData_t data;                       
+            // flood the transmission buffer of the BLE stack until it's full
+            do
+            {          
+                // TODO: poll and accumulate data
+                
+                // ...
+                
+                data.data = converter.data;
+                data.clock_us = 0;  
+                // write data in characteristic and repeat
+            } while (gattServer.write(sensorDataCharacteristic.getValueHandle(), reinterpret_cast<uint8_t*>(&data), sizeof(mpu6050SensorData_t)) == BLE_ERROR_NONE);
+            
+            // error case or buffer is full (or break out of loop);
+            // this also means the last data update will be lost, if not sent again 
+            // (we are ignoring this fact and just keep on going, because we're NOT interested in the QUALITY of data, but in the QUANTITY
+        }
+};
+
+#endif
\ No newline at end of file