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

Dependencies:   BLE_API mbed nRF51822 MPU6050_lib

Committer:
fruediger
Date:
Fri Jun 26 14:44:27 2015 +0000
Revision:
4:a97e6917f731
Parent:
3:d72d9195dc26
Child:
5:ea4d280a0a2f
tweaked blinky again =); + fixed battery monitoring

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