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

Dependencies:   BLE_API mbed nRF51822 MPU6050_lib

Committer:
fruediger
Date:
Tue Sep 08 13:42:58 2015 +0000
Revision:
10:b305e261e7d1
Parent:
9:6a28d9c0e486
Child:
12:dc46aa2edccd
mostly complete commit; too many minor changes to list them all...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
fruediger 1:6a40ad9ac7e5 1 /** Includes */
fruediger 1:6a40ad9ac7e5 2
fruediger 1:6a40ad9ac7e5 3 #include "common.h"
fruediger 0:23fd064af409 4 #include "mbed.h"
fruediger 0:23fd064af409 5 #include "BLE.h"
fruediger 3:d72d9195dc26 6 #include "MPU6050Service.h"
fruediger 10:b305e261e7d1 7 #include "PowerService.h"
fruediger 5:ea4d280a0a2f 8 #include "services/DeviceInformationService.h"
fruediger 10:b305e261e7d1 9 #include "MPU6050/helpers.h"
fruediger 1:6a40ad9ac7e5 10
fruediger 1:6a40ad9ac7e5 11 /** Constants */
fruediger 1:6a40ad9ac7e5 12
fruediger 9:6a28d9c0e486 13 static const char deviceName[] = "nano bear";
fruediger 9:6a28d9c0e486 14 static const char deviceManufacturers[] = "???";
fruediger 9:6a28d9c0e486 15 static const char deviceModelNumber[] = "";
fruediger 9:6a28d9c0e486 16 static const char deviceSerialNumber[] = XSTRING_(MBED_BUILD_TIMESTAMP);
fruediger 9:6a28d9c0e486 17 static const char deviceHardwareRev[] = "0.1";
fruediger 9:6a28d9c0e486 18 static const char deviceFirmwareRev[] = "0.1";
fruediger 9:6a28d9c0e486 19 static const char deviceSoftwareRev[] = "";
fruediger 1:6a40ad9ac7e5 20
fruediger 9:6a28d9c0e486 21 static const uint16_t minimumConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(20); // 20ms
fruediger 9:6a28d9c0e486 22 static const uint16_t maximumConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(40); // 40ms;
fruediger 9:6a28d9c0e486 23 static const uint16_t slaveLatency = 0;
fruediger 9:6a28d9c0e486 24
fruediger 10:b305e261e7d1 25 static const float ledTimeout = 0.05f;
fruediger 10:b305e261e7d1 26 static const uint8_t connectedBlinkSequ[] = { BYTE(11111111), BYTE(11111111), BYTE(11111111), BYTE(11111111),
fruediger 10:b305e261e7d1 27 BYTE(11111111), BYTE(11111111), BYTE(11111111), BYTE(11111111),
fruediger 10:b305e261e7d1 28 BYTE(11111111), BYTE(11111111), BYTE(11111111), BYTE(11000000),
fruediger 10:b305e261e7d1 29 BYTE(00000000) };
fruediger 10:b305e261e7d1 30 static const uint8_t disconnectedBlinkSequ[] = { BYTE(11111111), BYTE(11000000), BYTE(00001111), BYTE(11111100),
fruediger 10:b305e261e7d1 31 BYTE(00000000), BYTE(11111111), BYTE(11000000), BYTE(00001111),
fruediger 10:b305e261e7d1 32 BYTE(11111100), BYTE(00000000), BYTE(00000000) };
fruediger 10:b305e261e7d1 33 static const uint8_t batteryCritBlinkSequ[] = { BYTE(11111100), BYTE(00001111), BYTE(11000000) };
fruediger 7:af3e2b9c137a 34
fruediger 7:af3e2b9c137a 35 /** Power determination stuff:
fruediger 7:af3e2b9c137a 36 *
fruediger 7:af3e2b9c137a 37 * The following is the schematic circuit ...
fruediger 7:af3e2b9c137a 38 *
fruediger 7:af3e2b9c137a 39 * I0-> ____
fruediger 7:af3e2b9c137a 40 * --------*-|____|-*----------- ... where ...
fruediger 10:b305e261e7d1 41 * | | R3 | |
fruediger 7:af3e2b9c137a 42 * | | | _____|_____ |
fruediger 7:af3e2b9c137a 43 * | | | | | | | | | ____
fruediger 7:af3e2b9c137a 44 * | R1 | | R4 | | | BLE nano | | | and -|____|- are resistors ...
fruediger 7:af3e2b9c137a 45 * | |_| |_| | |--... |_|
fruediger 7:af3e2b9c137a 46 * | |~0-> | | | |
fruediger 7:af3e2b9c137a 47 * | Uref1 *--------|----| P0_4 |--...
fruediger 7:af3e2b9c137a 48 * + __|__ | |~0->| | ... and ...
fruediger 7:af3e2b9c137a 49 * U0 ___ | Uref2 *----| P0_5 |--...
fruediger 7:af3e2b9c137a 50 * | | | | | + __|__
fruediger 7:af3e2b9c137a 51 * | | | | | | |--... ___ is the constant voltage source
fruediger 7:af3e2b9c137a 52 * | R2 | | R5 | | | | | (a battery in this case)
fruediger 7:af3e2b9c137a 53 * | |_| |_| |___________|
fruediger 7:af3e2b9c137a 54 * | | | |
fruediger 7:af3e2b9c137a 55 * | | | |
fruediger 7:af3e2b9c137a 56 * *-------*--------*----------*--------...
fruediger 7:af3e2b9c137a 57 * _|_
fruediger 7:af3e2b9c137a 58 *
fruediger 7:af3e2b9c137a 59 *
fruediger 7:af3e2b9c137a 60 * Therefore the input values are
fruediger 7:af3e2b9c137a 61 *
fruediger 7:af3e2b9c137a 62 * U0 = (R1 / R2 + 1) * Uref1
fruediger 7:af3e2b9c137a 63 *
fruediger 7:af3e2b9c137a 64 * I0 = ((R1 + R3) / R2 + 1) / R3 * Uref1 - (R4 / R5 + 1) / R3 * Uref2
fruediger 7:af3e2b9c137a 65 *
fruediger 7:af3e2b9c137a 66 */
fruediger 7:af3e2b9c137a 67
fruediger 7:af3e2b9c137a 68 #define R1 1000.0f
fruediger 7:af3e2b9c137a 69 #define R2 1000.0f
fruediger 10:b305e261e7d1 70 #define R3 10.0f
fruediger 7:af3e2b9c137a 71 #define R4 1000.0f
fruediger 7:af3e2b9c137a 72 #define R5 1000.0f
fruediger 7:af3e2b9c137a 73 #define NANO_OP_VOLT 3.3f
fruediger 10:b305e261e7d1 74
fruediger 10:b305e261e7d1 75 static const float powerAccumulationTimeout = 0.005f;
fruediger 7:af3e2b9c137a 76
fruediger 9:6a28d9c0e486 77 static const float voltFac = ((R1 / R2) + 1.0f) * NANO_OP_VOLT;
fruediger 9:6a28d9c0e486 78 static const float currFac1 = ((((R1 + R3) / R2) + 1.0f) / R3) * NANO_OP_VOLT;
fruediger 9:6a28d9c0e486 79 static const float currFac2 = (((R4 / R5) + 1.0f) / R3) * NANO_OP_VOLT;
fruediger 9:6a28d9c0e486 80
fruediger 9:6a28d9c0e486 81 static const float powerServiceUpdateTimeout = 0.1f;
fruediger 1:6a40ad9ac7e5 82
fruediger 1:6a40ad9ac7e5 83
fruediger 1:6a40ad9ac7e5 84
fruediger 1:6a40ad9ac7e5 85 /** Global variables */
fruediger 1:6a40ad9ac7e5 86
fruediger 0:23fd064af409 87 BLE ble;
fruediger 0:23fd064af409 88 Gap::ConnectionParams_t fast;
fruediger 0:23fd064af409 89
fruediger 9:6a28d9c0e486 90 MPU6050 mpu(I2C_SDA0, I2C_SCL0, MPU6050::ADDRESS_0);
fruediger 0:23fd064af409 91
fruediger 10:b305e261e7d1 92 DigitalOut btLed(P0_28);
fruediger 10:b305e261e7d1 93 DigitalOut pwrLed(P0_29);
fruediger 9:6a28d9c0e486 94 DigitalOut aliveLed(LED);
fruediger 10:b305e261e7d1 95
fruediger 7:af3e2b9c137a 96 AnalogIn uRef1(P0_4);
fruediger 7:af3e2b9c137a 97 AnalogIn uRef2(P0_5);
fruediger 4:a97e6917f731 98
fruediger 9:6a28d9c0e486 99 Ticker powerAccumulationTicker;
fruediger 9:6a28d9c0e486 100 Ticker powerServiceUpdateTicker;
fruediger 10:b305e261e7d1 101 Ticker ledTicker;
fruediger 7:af3e2b9c137a 102
fruediger 1:6a40ad9ac7e5 103
fruediger 1:6a40ad9ac7e5 104
fruediger 9:6a28d9c0e486 105 /** Callback and handler functions */
fruediger 9:6a28d9c0e486 106
fruediger 9:6a28d9c0e486 107 // Accumulate discharge
fruediger 9:6a28d9c0e486 108
fruediger 9:6a28d9c0e486 109 static float U0 = 0.0f;
fruediger 9:6a28d9c0e486 110 static float I0 = 0.0f;
fruediger 9:6a28d9c0e486 111 static float Q = 0.0f;
fruediger 9:6a28d9c0e486 112
fruediger 9:6a28d9c0e486 113 void powerAccumulationPeriodicCallback()
fruediger 9:6a28d9c0e486 114 {
fruediger 9:6a28d9c0e486 115 // we have to do it in here, since we want a good approximation of the dt-timestep
fruediger 9:6a28d9c0e486 116 // since these are simple calculations this won't take much time
fruediger 9:6a28d9c0e486 117
fruediger 9:6a28d9c0e486 118 register float u1 = uRef1.read();
fruediger 9:6a28d9c0e486 119
fruediger 9:6a28d9c0e486 120 U0 = u1 * voltFac;
fruediger 9:6a28d9c0e486 121 I0 = (u1 * currFac1) - (uRef2.read() * currFac2);
fruediger 9:6a28d9c0e486 122 Q += I0 * powerAccumulationTimeout;
fruediger 9:6a28d9c0e486 123 }
fruediger 9:6a28d9c0e486 124
fruediger 9:6a28d9c0e486 125
fruediger 9:6a28d9c0e486 126
fruediger 9:6a28d9c0e486 127 // Update the power service characteristics
fruediger 9:6a28d9c0e486 128
fruediger 9:6a28d9c0e486 129 static bool powerServiceUpdateTrigger = false;
fruediger 1:6a40ad9ac7e5 130
fruediger 9:6a28d9c0e486 131 void powerServiceUpdateHandler(PowerService* powerService)
fruediger 9:6a28d9c0e486 132 {
fruediger 9:6a28d9c0e486 133 powerServiceUpdateTrigger = false;
fruediger 9:6a28d9c0e486 134
fruediger 9:6a28d9c0e486 135 powerService->updateVoltage(U0);
fruediger 9:6a28d9c0e486 136 powerService->updateCurrent(I0 * 1000);
fruediger 9:6a28d9c0e486 137 powerService->updateDischarge(Q * 0.277777777f);
fruediger 9:6a28d9c0e486 138 }
fruediger 9:6a28d9c0e486 139
fruediger 9:6a28d9c0e486 140 void powerServiceUpdatePeriodicCallback()
fruediger 9:6a28d9c0e486 141 {
fruediger 9:6a28d9c0e486 142 powerServiceUpdateTrigger = true;
fruediger 9:6a28d9c0e486 143 }
fruediger 9:6a28d9c0e486 144
fruediger 9:6a28d9c0e486 145
fruediger 9:6a28d9c0e486 146 // Update the bluetooth connection state LED
fruediger 9:6a28d9c0e486 147
fruediger 10:b305e261e7d1 148 static bool ledTrigger = false;
fruediger 10:b305e261e7d1 149 static bool batteryCritical = false;
fruediger 9:6a28d9c0e486 150
fruediger 10:b305e261e7d1 151 void ledHandler(Gap &gap, MPU6050Service *mpu)
fruediger 9:6a28d9c0e486 152 {
fruediger 10:b305e261e7d1 153 ledTrigger = false;
fruediger 9:6a28d9c0e486 154
fruediger 10:b305e261e7d1 155 static uint8_t byte = 0;
fruediger 10:b305e261e7d1 156 static uint8_t bit = 0;
fruediger 9:6a28d9c0e486 157
fruediger 10:b305e261e7d1 158 if (mpu->isRunning())
fruediger 10:b305e261e7d1 159 aliveLed = !aliveLed;
fruediger 3:d72d9195dc26 160
fruediger 9:6a28d9c0e486 161 if (gap.getState().connected)
fruediger 10:b305e261e7d1 162 btLed = (connectedBlinkSequ[byte % sizeof(connectedBlinkSequ)] >> bit) & 0x01;
fruediger 3:d72d9195dc26 163 else
fruediger 10:b305e261e7d1 164 btLed = (disconnectedBlinkSequ[byte % sizeof(connectedBlinkSequ)] >> bit) & 0x01;
fruediger 10:b305e261e7d1 165
fruediger 10:b305e261e7d1 166 if (batteryCritical)
fruediger 10:b305e261e7d1 167 pwrLed = (batteryCritBlinkSequ[byte % sizeof(batteryCritBlinkSequ)] >> bit) & 0x01;
fruediger 10:b305e261e7d1 168 else
fruediger 10:b305e261e7d1 169 pwrLed = 1;
fruediger 0:23fd064af409 170 }
fruediger 0:23fd064af409 171
fruediger 10:b305e261e7d1 172 void ledPeriodicCallback()
fruediger 0:23fd064af409 173 {
fruediger 10:b305e261e7d1 174 ledTrigger = true;
fruediger 9:6a28d9c0e486 175 }
fruediger 9:6a28d9c0e486 176
fruediger 9:6a28d9c0e486 177
fruediger 9:6a28d9c0e486 178
fruediger 9:6a28d9c0e486 179 // Connection timeout
fruediger 9:6a28d9c0e486 180
fruediger 9:6a28d9c0e486 181 static bool timeoutTrigger = false;
fruediger 9:6a28d9c0e486 182
fruediger 10:b305e261e7d1 183 void timeoutHandler(Gap &gap, MPU6050Service *mpu)
fruediger 9:6a28d9c0e486 184 {
fruediger 9:6a28d9c0e486 185 timeoutTrigger = false;
fruediger 4:a97e6917f731 186
fruediger 10:b305e261e7d1 187 mpu->stop();
fruediger 9:6a28d9c0e486 188 gap.startAdvertising();
fruediger 9:6a28d9c0e486 189 }
fruediger 9:6a28d9c0e486 190
fruediger 9:6a28d9c0e486 191 void timeoutCallback(Gap::TimeoutSource_t source)
fruediger 9:6a28d9c0e486 192 {
fruediger 9:6a28d9c0e486 193 timeoutTrigger = true;
fruediger 9:6a28d9c0e486 194 }
fruediger 9:6a28d9c0e486 195
fruediger 9:6a28d9c0e486 196
fruediger 9:6a28d9c0e486 197
fruediger 9:6a28d9c0e486 198 // Disconnection
fruediger 9:6a28d9c0e486 199
fruediger 9:6a28d9c0e486 200 static bool disconnectionTrigger = false;
fruediger 9:6a28d9c0e486 201
fruediger 10:b305e261e7d1 202 void disconnectionHandler(Gap &gap, MPU6050Service *mpu)
fruediger 9:6a28d9c0e486 203 {
fruediger 9:6a28d9c0e486 204 disconnectionTrigger = false;
fruediger 4:a97e6917f731 205
fruediger 10:b305e261e7d1 206 mpu->stop();
fruediger 9:6a28d9c0e486 207 gap.startAdvertising();
fruediger 0:23fd064af409 208 }
fruediger 0:23fd064af409 209
fruediger 0:23fd064af409 210 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
fruediger 0:23fd064af409 211 {
fruediger 9:6a28d9c0e486 212 timeoutTrigger = true;
fruediger 9:6a28d9c0e486 213 }
fruediger 9:6a28d9c0e486 214
fruediger 9:6a28d9c0e486 215
fruediger 9:6a28d9c0e486 216 // Connection
fruediger 9:6a28d9c0e486 217
fruediger 9:6a28d9c0e486 218 static bool connectionTrigger = false;
fruediger 9:6a28d9c0e486 219
fruediger 9:6a28d9c0e486 220 void connectionHandler(MPU6050Service *mpu6050)
fruediger 9:6a28d9c0e486 221 {
fruediger 9:6a28d9c0e486 222 connectionTrigger = false;
fruediger 4:a97e6917f731 223
fruediger 9:6a28d9c0e486 224 mpu6050->start();
fruediger 0:23fd064af409 225 }
fruediger 0:23fd064af409 226
fruediger 0:23fd064af409 227 void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
fruediger 9:6a28d9c0e486 228 {
fruediger 0:23fd064af409 229 // update the connection parameters with the tuned fast ones
fruediger 0:23fd064af409 230 ble.updateConnectionParams(params->handle, &fast);
fruediger 0:23fd064af409 231
fruediger 9:6a28d9c0e486 232 connectionTrigger = true;
fruediger 0:23fd064af409 233 }
fruediger 0:23fd064af409 234
fruediger 1:6a40ad9ac7e5 235
fruediger 1:6a40ad9ac7e5 236
fruediger 1:6a40ad9ac7e5 237 /** Main */
fruediger 1:6a40ad9ac7e5 238
fruediger 0:23fd064af409 239 int main()
fruediger 7:af3e2b9c137a 240 {
fruediger 10:b305e261e7d1 241 btLed = 1;
fruediger 10:b305e261e7d1 242 pwrLed = 1;
fruediger 9:6a28d9c0e486 243 aliveLed = 0;
fruediger 1:6a40ad9ac7e5 244
fruediger 9:6a28d9c0e486 245 ble.init();
fruediger 9:6a28d9c0e486 246
fruediger 9:6a28d9c0e486 247 Gap &gap = ble.gap();
fruediger 1:6a40ad9ac7e5 248
fruediger 9:6a28d9c0e486 249 powerAccumulationTicker.attach(powerAccumulationPeriodicCallback, powerAccumulationTimeout);
fruediger 9:6a28d9c0e486 250 powerServiceUpdateTicker.attach(powerServiceUpdatePeriodicCallback, powerServiceUpdateTimeout);
fruediger 10:b305e261e7d1 251 ledTicker.attach(ledPeriodicCallback, ledTimeout);
fruediger 0:23fd064af409 252
fruediger 9:6a28d9c0e486 253 gap.onTimeout(timeoutCallback);
fruediger 9:6a28d9c0e486 254 gap.onDisconnection(disconnectionCallback);
fruediger 9:6a28d9c0e486 255 gap.onConnection(connectionCallback);
fruediger 0:23fd064af409 256
fruediger 9:6a28d9c0e486 257 gap.setDeviceName((const uint8_t*)deviceName);
fruediger 0:23fd064af409 258
fruediger 9:6a28d9c0e486 259 gap.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
fruediger 9:6a28d9c0e486 260 gap.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t*)deviceName, sizeof(deviceName));
fruediger 9:6a28d9c0e486 261 gap.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
fruediger 0:23fd064af409 262
fruediger 0:23fd064af409 263 //TODO: DECISION: advertising at minimal interval may consumes to much power, but is way faster
fruediger 9:6a28d9c0e486 264 gap.setAdvertisingInterval(gap.getMinAdvertisingInterval());
fruediger 0:23fd064af409 265
fruediger 0:23fd064af409 266 // tune the preferred connection parameters to enable transfer more often
fruediger 0:23fd064af409 267 // TODO: DECISION: also waht about power consumption?
fruediger 9:6a28d9c0e486 268 gap.getPreferredConnectionParams(&fast);
fruediger 0:23fd064af409 269 fast.minConnectionInterval = minimumConnectionInterval;
fruediger 0:23fd064af409 270 fast.maxConnectionInterval = maximumConnectionInterval;
fruediger 0:23fd064af409 271 fast.slaveLatency = slaveLatency;
fruediger 9:6a28d9c0e486 272 gap.setPreferredConnectionParams(&fast);
fruediger 10:b305e261e7d1 273
fruediger 10:b305e261e7d1 274 DeviceInformationService deviceInformation(ble, &deviceManufacturers[0], deviceModelNumber, deviceSerialNumber, deviceHardwareRev, deviceFirmwareRev, deviceSoftwareRev);
fruediger 9:6a28d9c0e486 275 PowerService powerService(ble);
fruediger 10:b305e261e7d1 276 MPU6050Service mpu6050(ble, mpu, P0_9);
fruediger 5:ea4d280a0a2f 277
fruediger 9:6a28d9c0e486 278 gap.startAdvertising();
fruediger 7:af3e2b9c137a 279
fruediger 0:23fd064af409 280 while (true)
fruediger 9:6a28d9c0e486 281 {
fruediger 9:6a28d9c0e486 282 // Handle all stuff within the user context
fruediger 9:6a28d9c0e486 283
fruediger 9:6a28d9c0e486 284 if (powerServiceUpdateTrigger)
fruediger 9:6a28d9c0e486 285 powerServiceUpdateHandler(&powerService);
fruediger 9:6a28d9c0e486 286
fruediger 10:b305e261e7d1 287 if (ledTrigger)
fruediger 10:b305e261e7d1 288 ledHandler(gap, &mpu6050);
fruediger 9:6a28d9c0e486 289
fruediger 9:6a28d9c0e486 290 if (connectionTrigger)
fruediger 9:6a28d9c0e486 291 connectionHandler(&mpu6050);
fruediger 9:6a28d9c0e486 292
fruediger 9:6a28d9c0e486 293 if (disconnectionTrigger)
fruediger 10:b305e261e7d1 294 disconnectionHandler(gap, &mpu6050);
fruediger 9:6a28d9c0e486 295
fruediger 9:6a28d9c0e486 296 if (timeoutTrigger)
fruediger 10:b305e261e7d1 297 timeoutHandler(gap, &mpu6050);
fruediger 9:6a28d9c0e486 298
fruediger 0:23fd064af409 299 ble.waitForEvent();
fruediger 10:b305e261e7d1 300
fruediger 10:b305e261e7d1 301 mpu6050.handleService();
fruediger 9:6a28d9c0e486 302 }
fruediger 0:23fd064af409 303 }