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

Dependencies:   BLE_API mbed nRF51822 MPU6050_lib

Committer:
fruediger
Date:
Sat Jun 27 00:27:07 2015 +0000
Revision:
5:ea4d280a0a2f
Parent:
4:a97e6917f731
Child:
6:c1db7e82d76a
added DeviceInformationService; changed battery level analysis to work purely with integers

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 4:a97e6917f731 7 #include "services/BatteryService.h"
fruediger 5:ea4d280a0a2f 8 #include "services/DeviceInformationService.h"
fruediger 1:6a40ad9ac7e5 9
fruediger 1:6a40ad9ac7e5 10 /** Constants */
fruediger 1:6a40ad9ac7e5 11
fruediger 1:6a40ad9ac7e5 12 static const char deviceName[] = "nano bear " XSTRING_(MBED_BUILD_TIMESTAMP);
fruediger 5:ea4d280a0a2f 13 static const char deviceManufacturers[] = "???";
fruediger 5:ea4d280a0a2f 14 static const char deviceModelNumber[] = "";
fruediger 5:ea4d280a0a2f 15 static const char deviceSerialNumber[] = XSTRING_(MBED_BUILD_TIMESTAMP);
fruediger 5:ea4d280a0a2f 16 static const char deviceHardwareRev[] = "0.1";
fruediger 5:ea4d280a0a2f 17 static const char deviceFirmwareRev[] = "0.1";
fruediger 5:ea4d280a0a2f 18 static const char deviceSoftwareRev[] = "";
fruediger 1:6a40ad9ac7e5 19
fruediger 0:23fd064af409 20 static const uint16_t minimumConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(20); // 20ms
fruediger 0:23fd064af409 21 static const uint16_t maximumConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(40); // 40ms;
fruediger 0:23fd064af409 22 static const uint16_t slaveLatency = 0;
fruediger 0:23fd064af409 23
fruediger 4:a97e6917f731 24 static const float tickerTimeout = 0.05f;
fruediger 4:a97e6917f731 25 static const float batteryCritBlinkSequ[] = { 0.000f, 0.146f, 0.500f, 0.854f, 1.000f, 0.854f, 0.500f, 0.146f };
fruediger 4:a97e6917f731 26 static const float connectedBlinkSequ[] = { 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 5:ea4d280a0a2f 27 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 5:ea4d280a0a2f 28 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 5:ea4d280a0a2f 29 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 4:a97e6917f731 30 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 4:a97e6917f731 31 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f, 1.000f,
fruediger 4:a97e6917f731 32 1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
fruediger 4:a97e6917f731 33 0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f };
fruediger 4:a97e6917f731 34 static const float disconnectedBlinkSequ[] = { 0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
fruediger 4:a97e6917f731 35 1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
fruediger 4:a97e6917f731 36 0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
fruediger 4:a97e6917f731 37 1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
fruediger 4:a97e6917f731 38 0.000f, 0.038f, 0.146f, 0.309f, 0.500f, 0.691f, 0.854f, 0.962f,
fruediger 4:a97e6917f731 39 1.000f, 0.962f, 0.854f, 0.691f, 0.500f, 0.309f, 0.146f, 0.038f,
fruediger 4:a97e6917f731 40 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f,
fruediger 4:a97e6917f731 41 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f,
fruediger 4:a97e6917f731 42 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f, 0.000f };
fruediger 4:a97e6917f731 43
fruediger 4:a97e6917f731 44 static const float batteryLevelRescale = 3.3f / 3.0f; // mbed ref. voltage / expected battery maximum (pulled down through a potential divider)
fruediger 5:ea4d280a0a2f 45 static const uint8_t batteryCritThreshold = 30; // 30%
fruediger 1:6a40ad9ac7e5 46
fruediger 1:6a40ad9ac7e5 47
fruediger 1:6a40ad9ac7e5 48
fruediger 1:6a40ad9ac7e5 49 /** Global variables */
fruediger 1:6a40ad9ac7e5 50
fruediger 3:d72d9195dc26 51 Serial pc(USBTX, USBRX);
fruediger 3:d72d9195dc26 52
fruediger 0:23fd064af409 53 BLE ble;
fruediger 0:23fd064af409 54 Gap::ConnectionParams_t fast;
fruediger 0:23fd064af409 55
fruediger 4:a97e6917f731 56 BatteryService *battery = NULL;
fruediger 5:ea4d280a0a2f 57 DeviceInformationService *deviceInformation = NULL;
fruediger 4:a97e6917f731 58 MPU6050Service *mpu6050 = NULL;
fruediger 0:23fd064af409 59
fruediger 4:a97e6917f731 60 PwmOut btLed(P0_28);
fruediger 4:a97e6917f731 61 PwmOut batLed(P0_29);
fruediger 4:a97e6917f731 62 DigitalOut aliveLed(LED1);
fruediger 4:a97e6917f731 63 AnalogIn batLevel(P0_4);
fruediger 4:a97e6917f731 64
fruediger 0:23fd064af409 65 Ticker ticker;
fruediger 0:23fd064af409 66
fruediger 1:6a40ad9ac7e5 67
fruediger 3:d72d9195dc26 68 /** Helpers */
fruediger 1:6a40ad9ac7e5 69
fruediger 0:23fd064af409 70 inline Gap &gap()
fruediger 0:23fd064af409 71 {
fruediger 0:23fd064af409 72 // get us the corresponding Gap instance only once and then save and reuse that instance
fruediger 0:23fd064af409 73 // (the underlying Gap instance shouldn't change on the BLE object)
fruediger 0:23fd064af409 74 static Gap &gap = ble.gap();
fruediger 0:23fd064af409 75 return gap;
fruediger 0:23fd064af409 76 }
fruediger 0:23fd064af409 77
fruediger 1:6a40ad9ac7e5 78
fruediger 1:6a40ad9ac7e5 79
fruediger 1:6a40ad9ac7e5 80 /** Callback functions */
fruediger 1:6a40ad9ac7e5 81
fruediger 0:23fd064af409 82 void periodicCallback()
fruediger 4:a97e6917f731 83 {
fruediger 4:a97e6917f731 84 static int batCnt = -1;
fruediger 4:a97e6917f731 85 static int conCnt = -1;
fruediger 4:a97e6917f731 86 static const int batteryCritBlinkSequSize = sizeof(batteryCritBlinkSequ) / sizeof(float);
fruediger 3:d72d9195dc26 87 static const int connectedBlinkSequSize = sizeof(connectedBlinkSequ) / sizeof(float);
fruediger 3:d72d9195dc26 88 static const int disconnectedBlinkSequSize = sizeof(disconnectedBlinkSequ) / sizeof(float);
fruediger 3:d72d9195dc26 89
fruediger 4:a97e6917f731 90 // alive state led
fruediger 4:a97e6917f731 91
fruediger 4:a97e6917f731 92 aliveLed = !aliveLed;
fruediger 4:a97e6917f731 93
fruediger 4:a97e6917f731 94 // battery level led
fruediger 4:a97e6917f731 95
fruediger 5:ea4d280a0a2f 96 uint8_t batteryLevel = (uint8_t)(batteryLevelRescale * batLevel * 100.0f);
fruediger 5:ea4d280a0a2f 97 if (batteryLevel > 100)
fruediger 4:a97e6917f731 98 {
fruediger 5:ea4d280a0a2f 99 batteryLevel = 100;
fruediger 4:a97e6917f731 100 batLed = 1.0f;
fruediger 4:a97e6917f731 101 }
fruediger 5:ea4d280a0a2f 102 else if (batteryLevel <= batteryCritThreshold)
fruediger 4:a97e6917f731 103 {
fruediger 4:a97e6917f731 104 batCnt = (batCnt + 1) % (batteryCritBlinkSequSize);
fruediger 4:a97e6917f731 105 batLed = batteryCritBlinkSequ[batCnt];
fruediger 4:a97e6917f731 106 }
fruediger 4:a97e6917f731 107 else
fruediger 4:a97e6917f731 108 batLed = 1.0f;
fruediger 4:a97e6917f731 109
fruediger 5:ea4d280a0a2f 110 // also update BatteryService characteristic if needed
fruediger 4:a97e6917f731 111
fruediger 5:ea4d280a0a2f 112 static uint8_t oldBatteryLevel = 0xFF;
fruediger 5:ea4d280a0a2f 113 if (batteryLevel != oldBatteryLevel && battery != NULL)
fruediger 5:ea4d280a0a2f 114 {
fruediger 5:ea4d280a0a2f 115 battery->updateBatteryLevel(batteryLevel);
fruediger 4:a97e6917f731 116
fruediger 5:ea4d280a0a2f 117 pc.printf("Battery level is now: %i%%.", batteryLevel);
fruediger 4:a97e6917f731 118
fruediger 5:ea4d280a0a2f 119 oldBatteryLevel = batteryLevel;
fruediger 4:a97e6917f731 120 }
fruediger 4:a97e6917f731 121
fruediger 4:a97e6917f731 122 // bluetooth connection state led
fruediger 4:a97e6917f731 123
fruediger 3:d72d9195dc26 124 if (gap().getState().connected)
fruediger 3:d72d9195dc26 125 {
fruediger 4:a97e6917f731 126 conCnt = ((conCnt + 1) % connectedBlinkSequSize);
fruediger 4:a97e6917f731 127 btLed = connectedBlinkSequ[conCnt];
fruediger 3:d72d9195dc26 128 }
fruediger 3:d72d9195dc26 129 else
fruediger 3:d72d9195dc26 130 {
fruediger 4:a97e6917f731 131 conCnt = ((conCnt + 1) % disconnectedBlinkSequSize);
fruediger 4:a97e6917f731 132 btLed = disconnectedBlinkSequ[conCnt];
fruediger 4:a97e6917f731 133 }
fruediger 0:23fd064af409 134 }
fruediger 0:23fd064af409 135
fruediger 4:a97e6917f731 136 void timeoutCallback(Gap::TimeoutSource_t source)
fruediger 0:23fd064af409 137 {
fruediger 4:a97e6917f731 138 pc.printf("Got TIMEOUT ");
fruediger 4:a97e6917f731 139 switch (source)
fruediger 4:a97e6917f731 140 {
fruediger 4:a97e6917f731 141 case Gap::TIMEOUT_SRC_ADVERTISING: pc.printf("while advertising!\n\r"); break;
fruediger 4:a97e6917f731 142 case Gap::TIMEOUT_SRC_SECURITY_REQUEST: pc.printf("during security request!\n\r"); break;
fruediger 4:a97e6917f731 143 case Gap::TIMEOUT_SRC_SCAN: pc.printf("while scanning!\n\r"); break;
fruediger 4:a97e6917f731 144 case Gap::TIMEOUT_SRC_CONN: pc.printf("during connection!\n\r"); break;
fruediger 4:a97e6917f731 145 }
fruediger 4:a97e6917f731 146
fruediger 0:23fd064af409 147 gap().startAdvertising();
fruediger 4:a97e6917f731 148
fruediger 4:a97e6917f731 149 pc.printf("Restarting ADVERTISING...\n\r");
fruediger 0:23fd064af409 150 }
fruediger 0:23fd064af409 151
fruediger 0:23fd064af409 152 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
fruediger 0:23fd064af409 153 {
fruediger 4:a97e6917f731 154 pc.printf("DISCONNECTED because ");
fruediger 4:a97e6917f731 155 switch (reason)
fruediger 4:a97e6917f731 156 {
fruediger 4:a97e6917f731 157 case Gap::CONNECTION_TIMEOUT: pc.printf("of connection timeout!\n\r"); break;
fruediger 4:a97e6917f731 158 case Gap::REMOTE_USER_TERMINATED_CONNECTION: pc.printf("the remote user terminated the connection!\n\r"); break;
fruediger 4:a97e6917f731 159 case Gap::REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES: pc.printf("the remote device is low on resources!\n\r"); break;
fruediger 4:a97e6917f731 160 case Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF: pc.printf("the remote device is off!\n\r"); break;
fruediger 4:a97e6917f731 161 case Gap::LOCAL_HOST_TERMINATED_CONNECTION: pc.printf("we terminated the connection!\n\r"); break;
fruediger 4:a97e6917f731 162 case Gap::CONN_INTERVAL_UNACCEPTABLE: pc.printf("the connection interval is unacceptable!\n\r"); break;
fruediger 4:a97e6917f731 163 }
fruediger 4:a97e6917f731 164
fruediger 0:23fd064af409 165 gap().startAdvertising();
fruediger 4:a97e6917f731 166
fruediger 4:a97e6917f731 167 pc.printf("Restarting ADVERTISING...\n\r");
fruediger 0:23fd064af409 168 }
fruediger 0:23fd064af409 169
fruediger 0:23fd064af409 170 void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
fruediger 0:23fd064af409 171 {
fruediger 4:a97e6917f731 172 pc.printf("Got a CONNECTION from %02X:%02X:%02X:%02X:%02X:%02X (we are a ", (params->peerAddr)[0], (params->peerAddr)[1], (params->peerAddr)[2], (params->peerAddr)[3], (params->peerAddr)[4], (params->peerAddr)[5]);
fruediger 4:a97e6917f731 173
fruediger 4:a97e6917f731 174 switch(params->role)
fruediger 4:a97e6917f731 175 {
fruediger 4:a97e6917f731 176 case Gap::PERIPHERAL: pc.printf("peripheral)!\n\r"); break;
fruediger 4:a97e6917f731 177 case Gap::CENTRAL: pc.printf("central)!\n\r"); break;
fruediger 4:a97e6917f731 178 }
fruediger 4:a97e6917f731 179
fruediger 4:a97e6917f731 180 pc.printf("Updating connection parameters to be faster...\n\r");
fruediger 4:a97e6917f731 181
fruediger 0:23fd064af409 182 // update the connection parameters with the tuned fast ones
fruediger 0:23fd064af409 183 ble.updateConnectionParams(params->handle, &fast);
fruediger 0:23fd064af409 184
fruediger 4:a97e6917f731 185 pc.printf("Starting MPU-6050 service...\n\r");
fruediger 4:a97e6917f731 186
fruediger 0:23fd064af409 187 // start polling and sending sensor data
fruediger 3:d72d9195dc26 188 mpu6050->start();
fruediger 0:23fd064af409 189 }
fruediger 0:23fd064af409 190
fruediger 1:6a40ad9ac7e5 191
fruediger 1:6a40ad9ac7e5 192
fruediger 1:6a40ad9ac7e5 193 /** Main */
fruediger 1:6a40ad9ac7e5 194
fruediger 0:23fd064af409 195 int main()
fruediger 1:6a40ad9ac7e5 196 {
fruediger 4:a97e6917f731 197 btLed = 1.0f;
fruediger 4:a97e6917f731 198 batLed = 1.0f;
fruediger 4:a97e6917f731 199 aliveLed = 1;
fruediger 1:6a40ad9ac7e5 200
fruediger 0:23fd064af409 201 ble.init();
fruediger 1:6a40ad9ac7e5 202
fruediger 1:6a40ad9ac7e5 203 ticker.attach(periodicCallback, tickerTimeout);
fruediger 0:23fd064af409 204
fruediger 0:23fd064af409 205 gap().onTimeout(timeoutCallback);
fruediger 0:23fd064af409 206 gap().onDisconnection(disconnectionCallback);
fruediger 0:23fd064af409 207 gap().onConnection(connectionCallback);
fruediger 0:23fd064af409 208
fruediger 0:23fd064af409 209 gap().setDeviceName((const uint8_t*)deviceName);
fruediger 0:23fd064af409 210
fruediger 0:23fd064af409 211 gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
fruediger 0:23fd064af409 212 gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (const uint8_t*)deviceName, sizeof(deviceName));
fruediger 0:23fd064af409 213 gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
fruediger 0:23fd064af409 214
fruediger 0:23fd064af409 215 //TODO: DECISION: advertising at minimal interval may consumes to much power, but is way faster
fruediger 0:23fd064af409 216 gap().setAdvertisingInterval(gap().getMinAdvertisingInterval());
fruediger 0:23fd064af409 217
fruediger 0:23fd064af409 218 // tune the preferred connection parameters to enable transfer more often
fruediger 0:23fd064af409 219 // TODO: DECISION: also waht about power consumption?
fruediger 0:23fd064af409 220 gap().getPreferredConnectionParams(&fast);
fruediger 0:23fd064af409 221 fast.minConnectionInterval = minimumConnectionInterval;
fruediger 0:23fd064af409 222 fast.maxConnectionInterval = maximumConnectionInterval;
fruediger 0:23fd064af409 223 fast.slaveLatency = slaveLatency;
fruediger 0:23fd064af409 224 gap().setPreferredConnectionParams(&fast);
fruediger 0:23fd064af409 225
fruediger 0:23fd064af409 226 gap().startAdvertising();
fruediger 0:23fd064af409 227
fruediger 4:a97e6917f731 228 pc.printf("Start ADVERTISING...\n\r");
fruediger 4:a97e6917f731 229
fruediger 5:ea4d280a0a2f 230 BatteryService _battery(ble);
fruediger 5:ea4d280a0a2f 231 battery = &_battery;
fruediger 5:ea4d280a0a2f 232
fruediger 5:ea4d280a0a2f 233 DeviceInformationService _deviceInformation(ble, deviceManufacturers, deviceModelNumber, deviceSerialNumber, deviceHardwareRev, deviceFirmwareRev, deviceSoftwareRev);
fruediger 5:ea4d280a0a2f 234 deviceInformation = &_deviceInformation;
fruediger 5:ea4d280a0a2f 235
fruediger 5:ea4d280a0a2f 236 MPU6050Service _mpu6050(ble);
fruediger 5:ea4d280a0a2f 237 mpu6050 = &_mpu6050;
fruediger 0:23fd064af409 238
fruediger 0:23fd064af409 239 while (true)
fruediger 0:23fd064af409 240 ble.waitForEvent();
fruediger 0:23fd064af409 241 }