
BLE GATT-service implementation for high quantity sensor data from a MPU6050-accelerator/gyroscope
Dependencies: BLE_API mbed nRF51822 MPU6050_lib
main.cpp@5:ea4d280a0a2f, 2015-06-27 (annotated)
- 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?
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 | 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 | } |