
BLE GATT-service implementation for high quantity sensor data from a MPU6050-accelerator/gyroscope
Dependencies: BLE_API mbed nRF51822 MPU6050_lib
main.cpp@4:a97e6917f731, 2015-06-26 (annotated)
- 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?
User | Revision | Line number | New 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 | } |