An example program to test data transfer throughput. Exhibits long latency (2 sec) between hardware callbacks on write event.
Dependencies: BLE_API mbed nRF51822
TransferService.cpp@0:ab775bf55fe4, 2014-08-14 (annotated)
- Committer:
- pvaibhav
- Date:
- Thu Aug 14 14:13:53 2014 +0000
- Revision:
- 0:ab775bf55fe4
Minimal program to demo slow throughput/callback latency
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pvaibhav | 0:ab775bf55fe4 | 1 | #include "TransferService.h" |
pvaibhav | 0:ab775bf55fe4 | 2 | #include "Logger.h" |
pvaibhav | 0:ab775bf55fe4 | 3 | #include "Configuration.h" |
pvaibhav | 0:ab775bf55fe4 | 4 | |
pvaibhav | 0:ab775bf55fe4 | 5 | namespace Transfer |
pvaibhav | 0:ab775bf55fe4 | 6 | { |
pvaibhav | 0:ab775bf55fe4 | 7 | |
pvaibhav | 0:ab775bf55fe4 | 8 | // Transfer base UUID: ADC710C2-xxxx-4BF5-8244-3CEAAA0F87F5 |
pvaibhav | 0:ab775bf55fe4 | 9 | #define transfer_UUID(x) { 0xAD, 0xC7, 0x10, 0xC2, (((x) & 0xFF00) >> 8), ((x) & 0xFF), 0x4B, 0xF5, 0x82, 0x44, 0x3C, 0xEA, 0xAA, 0x0F, 0x87, 0xF5 } |
pvaibhav | 0:ab775bf55fe4 | 10 | |
pvaibhav | 0:ab775bf55fe4 | 11 | // UUID byte arrays |
pvaibhav | 0:ab775bf55fe4 | 12 | static const uint8_t transferServiceUUID[] = transfer_UUID(0xACDC); |
pvaibhav | 0:ab775bf55fe4 | 13 | static const uint8_t transferFileInfoUUID[] = transfer_UUID(0xACDF); |
pvaibhav | 0:ab775bf55fe4 | 14 | static const uint8_t transferFileBlocksUUID[6][16] = |
pvaibhav | 0:ab775bf55fe4 | 15 | { |
pvaibhav | 0:ab775bf55fe4 | 16 | transfer_UUID(0xACE0), |
pvaibhav | 0:ab775bf55fe4 | 17 | transfer_UUID(0xACE1), |
pvaibhav | 0:ab775bf55fe4 | 18 | transfer_UUID(0xACE2), |
pvaibhav | 0:ab775bf55fe4 | 19 | transfer_UUID(0xACE3), |
pvaibhav | 0:ab775bf55fe4 | 20 | transfer_UUID(0xACE4), |
pvaibhav | 0:ab775bf55fe4 | 21 | transfer_UUID(0xACE5), |
pvaibhav | 0:ab775bf55fe4 | 22 | }; |
pvaibhav | 0:ab775bf55fe4 | 23 | |
pvaibhav | 0:ab775bf55fe4 | 24 | // UUID objects used to initialise Bluetooth API |
pvaibhav | 0:ab775bf55fe4 | 25 | static UUID transferServiceUUID_ = UUID(transferServiceUUID); |
pvaibhav | 0:ab775bf55fe4 | 26 | static UUID transferFileInfoUUID_ = UUID(transferFileInfoUUID); |
pvaibhav | 0:ab775bf55fe4 | 27 | static UUID transferFileBlocksUUID_[6] = |
pvaibhav | 0:ab775bf55fe4 | 28 | { |
pvaibhav | 0:ab775bf55fe4 | 29 | UUID(transferFileBlocksUUID[0]), |
pvaibhav | 0:ab775bf55fe4 | 30 | UUID(transferFileBlocksUUID[1]), |
pvaibhav | 0:ab775bf55fe4 | 31 | UUID(transferFileBlocksUUID[2]), |
pvaibhav | 0:ab775bf55fe4 | 32 | UUID(transferFileBlocksUUID[3]), |
pvaibhav | 0:ab775bf55fe4 | 33 | UUID(transferFileBlocksUUID[4]), |
pvaibhav | 0:ab775bf55fe4 | 34 | UUID(transferFileBlocksUUID[5]), |
pvaibhav | 0:ab775bf55fe4 | 35 | }; |
pvaibhav | 0:ab775bf55fe4 | 36 | |
pvaibhav | 0:ab775bf55fe4 | 37 | // Storage for the value of the characteristics |
pvaibhav | 0:ab775bf55fe4 | 38 | struct fileInfo_t { |
pvaibhav | 0:ab775bf55fe4 | 39 | uint16_t length; |
pvaibhav | 0:ab775bf55fe4 | 40 | uint16_t crc16; |
pvaibhav | 0:ab775bf55fe4 | 41 | }; |
pvaibhav | 0:ab775bf55fe4 | 42 | static struct fileInfo_t fileInfo; |
pvaibhav | 0:ab775bf55fe4 | 43 | struct fileBlock_t { |
pvaibhav | 0:ab775bf55fe4 | 44 | uint16_t blockNumber; |
pvaibhav | 0:ab775bf55fe4 | 45 | uint8_t data[16]; |
pvaibhav | 0:ab775bf55fe4 | 46 | }; |
pvaibhav | 0:ab775bf55fe4 | 47 | static struct fileBlock_t fileBlocks[6]; // 6 blocks |
pvaibhav | 0:ab775bf55fe4 | 48 | |
pvaibhav | 0:ab775bf55fe4 | 49 | // Other things needed for operation |
pvaibhav | 0:ab775bf55fe4 | 50 | static BLEDevice* ble; |
pvaibhav | 0:ab775bf55fe4 | 51 | static Timer downloadTimer; |
pvaibhav | 0:ab775bf55fe4 | 52 | |
pvaibhav | 0:ab775bf55fe4 | 53 | static uint16_t expectingBlock = 0; |
pvaibhav | 0:ab775bf55fe4 | 54 | |
pvaibhav | 0:ab775bf55fe4 | 55 | static bool acceptFile = true; // additional condition whether to accept a file upload or not, currently always accept |
pvaibhav | 0:ab775bf55fe4 | 56 | static bool downloadInProgress = false; // indicates if we are downloading a file from the phone |
pvaibhav | 0:ab775bf55fe4 | 57 | |
pvaibhav | 0:ab775bf55fe4 | 58 | static GattCharacteristic transferFileInfo(transferFileInfoUUID_, |
pvaibhav | 0:ab775bf55fe4 | 59 | (uint8_t*) &fileInfo, |
pvaibhav | 0:ab775bf55fe4 | 60 | sizeof(fileInfo), |
pvaibhav | 0:ab775bf55fe4 | 61 | sizeof(fileInfo), |
pvaibhav | 0:ab775bf55fe4 | 62 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
pvaibhav | 0:ab775bf55fe4 | 63 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); |
pvaibhav | 0:ab775bf55fe4 | 64 | |
pvaibhav | 0:ab775bf55fe4 | 65 | static uint8_t fileBlockProperties = |
pvaibhav | 0:ab775bf55fe4 | 66 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
pvaibhav | 0:ab775bf55fe4 | 67 | | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE; |
pvaibhav | 0:ab775bf55fe4 | 68 | |
pvaibhav | 0:ab775bf55fe4 | 69 | static GattCharacteristic transferFileBlocks[6] = { |
pvaibhav | 0:ab775bf55fe4 | 70 | GattCharacteristic(transferFileBlocksUUID_[0], (uint8_t*) &fileBlocks[0], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 71 | GattCharacteristic(transferFileBlocksUUID_[1], (uint8_t*) &fileBlocks[1], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 72 | GattCharacteristic(transferFileBlocksUUID_[2], (uint8_t*) &fileBlocks[2], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 73 | GattCharacteristic(transferFileBlocksUUID_[3], (uint8_t*) &fileBlocks[3], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 74 | GattCharacteristic(transferFileBlocksUUID_[4], (uint8_t*) &fileBlocks[4], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 75 | GattCharacteristic(transferFileBlocksUUID_[5], (uint8_t*) &fileBlocks[5], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), |
pvaibhav | 0:ab775bf55fe4 | 76 | }; |
pvaibhav | 0:ab775bf55fe4 | 77 | |
pvaibhav | 0:ab775bf55fe4 | 78 | static GattCharacteristic* allChars[] = |
pvaibhav | 0:ab775bf55fe4 | 79 | { |
pvaibhav | 0:ab775bf55fe4 | 80 | &transferFileInfo, |
pvaibhav | 0:ab775bf55fe4 | 81 | &transferFileBlocks[0], |
pvaibhav | 0:ab775bf55fe4 | 82 | &transferFileBlocks[1], |
pvaibhav | 0:ab775bf55fe4 | 83 | &transferFileBlocks[2], |
pvaibhav | 0:ab775bf55fe4 | 84 | &transferFileBlocks[3], |
pvaibhav | 0:ab775bf55fe4 | 85 | &transferFileBlocks[4], |
pvaibhav | 0:ab775bf55fe4 | 86 | &transferFileBlocks[5], |
pvaibhav | 0:ab775bf55fe4 | 87 | }; |
pvaibhav | 0:ab775bf55fe4 | 88 | |
pvaibhav | 0:ab775bf55fe4 | 89 | static GattService transferService(transferServiceUUID_, allChars, sizeof(allChars) / sizeof(GattCharacteristic*)); |
pvaibhav | 0:ab775bf55fe4 | 90 | |
pvaibhav | 0:ab775bf55fe4 | 91 | void init(BLEDevice &bleDevice) |
pvaibhav | 0:ab775bf55fe4 | 92 | { |
pvaibhav | 0:ab775bf55fe4 | 93 | downloadInProgress = false; |
pvaibhav | 0:ab775bf55fe4 | 94 | ble = &bleDevice; |
pvaibhav | 0:ab775bf55fe4 | 95 | ble->addService(transferService); |
pvaibhav | 0:ab775bf55fe4 | 96 | DEBUG("Added transfer service\r\n"); |
pvaibhav | 0:ab775bf55fe4 | 97 | } |
pvaibhav | 0:ab775bf55fe4 | 98 | |
pvaibhav | 0:ab775bf55fe4 | 99 | void reset() |
pvaibhav | 0:ab775bf55fe4 | 100 | { |
pvaibhav | 0:ab775bf55fe4 | 101 | // reset internal state on new connection |
pvaibhav | 0:ab775bf55fe4 | 102 | downloadInProgress = false; |
pvaibhav | 0:ab775bf55fe4 | 103 | } |
pvaibhav | 0:ab775bf55fe4 | 104 | |
pvaibhav | 0:ab775bf55fe4 | 105 | const uint8_t* getServiceUUIDp() |
pvaibhav | 0:ab775bf55fe4 | 106 | { |
pvaibhav | 0:ab775bf55fe4 | 107 | return transferServiceUUID; |
pvaibhav | 0:ab775bf55fe4 | 108 | } |
pvaibhav | 0:ab775bf55fe4 | 109 | |
pvaibhav | 0:ab775bf55fe4 | 110 | void requestBlock(uint16_t); // prototype declaration |
pvaibhav | 0:ab775bf55fe4 | 111 | void sendFileInfo(); |
pvaibhav | 0:ab775bf55fe4 | 112 | void refuseFile(); |
pvaibhav | 0:ab775bf55fe4 | 113 | void sendFileDownloadedSuccessfully(); |
pvaibhav | 0:ab775bf55fe4 | 114 | |
pvaibhav | 0:ab775bf55fe4 | 115 | void handleDataWritten(uint16_t handle) |
pvaibhav | 0:ab775bf55fe4 | 116 | { |
pvaibhav | 0:ab775bf55fe4 | 117 | if (!ble) |
pvaibhav | 0:ab775bf55fe4 | 118 | return; |
pvaibhav | 0:ab775bf55fe4 | 119 | |
pvaibhav | 0:ab775bf55fe4 | 120 | int channel = expectingBlock % 6; |
pvaibhav | 0:ab775bf55fe4 | 121 | |
pvaibhav | 0:ab775bf55fe4 | 122 | if (handle == transferFileInfo.getHandle()) { |
pvaibhav | 0:ab775bf55fe4 | 123 | |
pvaibhav | 0:ab775bf55fe4 | 124 | uint16_t len = sizeof(fileInfo); |
pvaibhav | 0:ab775bf55fe4 | 125 | ble->readCharacteristicValue(handle, (uint8_t*) &fileInfo, &len); |
pvaibhav | 0:ab775bf55fe4 | 126 | |
pvaibhav | 0:ab775bf55fe4 | 127 | if (fileInfo.length == 0 && fileInfo.crc16 == 0) { |
pvaibhav | 0:ab775bf55fe4 | 128 | // signal to cancel pending upload |
pvaibhav | 0:ab775bf55fe4 | 129 | downloadInProgress = false; |
pvaibhav | 0:ab775bf55fe4 | 130 | downloadTimer.reset(); |
pvaibhav | 0:ab775bf55fe4 | 131 | expectingBlock = 0; |
pvaibhav | 0:ab775bf55fe4 | 132 | DEBUG("Download RESET\r\n"); |
pvaibhav | 0:ab775bf55fe4 | 133 | return; |
pvaibhav | 0:ab775bf55fe4 | 134 | } |
pvaibhav | 0:ab775bf55fe4 | 135 | |
pvaibhav | 0:ab775bf55fe4 | 136 | DEBUG("Offered file len=%d, crc=0x%04x, acceptFile=%d, downloadInProgress=%d\r\n", fileInfo.length, fileInfo.crc16, acceptFile, downloadInProgress); |
pvaibhav | 0:ab775bf55fe4 | 137 | |
pvaibhav | 0:ab775bf55fe4 | 138 | // Now we must decide whether to accept it or not |
pvaibhav | 0:ab775bf55fe4 | 139 | if (acceptFile && !downloadInProgress) { |
pvaibhav | 0:ab775bf55fe4 | 140 | downloadTimer.reset(); |
pvaibhav | 0:ab775bf55fe4 | 141 | downloadTimer.start(); |
pvaibhav | 0:ab775bf55fe4 | 142 | downloadInProgress = true; |
pvaibhav | 0:ab775bf55fe4 | 143 | requestBlock(0); |
pvaibhav | 0:ab775bf55fe4 | 144 | } else |
pvaibhav | 0:ab775bf55fe4 | 145 | refuseFile(); |
pvaibhav | 0:ab775bf55fe4 | 146 | |
pvaibhav | 0:ab775bf55fe4 | 147 | } else if (handle == transferFileBlocks[channel].getHandle()) { |
pvaibhav | 0:ab775bf55fe4 | 148 | |
pvaibhav | 0:ab775bf55fe4 | 149 | uint16_t len = sizeof(fileBlocks[channel]); |
pvaibhav | 0:ab775bf55fe4 | 150 | ble->readCharacteristicValue(handle, (uint8_t*) &fileBlocks[channel], &len); |
pvaibhav | 0:ab775bf55fe4 | 151 | |
pvaibhav | 0:ab775bf55fe4 | 152 | //DEBUG("blk %d on ch %d (total %d)", fileBlocks[channel].blockNumber, channel, ++blk) |
pvaibhav | 0:ab775bf55fe4 | 153 | //DEBUG("."); |
pvaibhav | 0:ab775bf55fe4 | 154 | /* |
pvaibhav | 0:ab775bf55fe4 | 155 | uint8_t byte; |
pvaibhav | 0:ab775bf55fe4 | 156 | for (int i = 2; i < len; i++) { |
pvaibhav | 0:ab775bf55fe4 | 157 | byte = *(((uint8_t*) &fileBlock) + i); |
pvaibhav | 0:ab775bf55fe4 | 158 | DEBUG("%c", byte, byte); |
pvaibhav | 0:ab775bf55fe4 | 159 | } |
pvaibhav | 0:ab775bf55fe4 | 160 | */ |
pvaibhav | 0:ab775bf55fe4 | 161 | |
pvaibhav | 0:ab775bf55fe4 | 162 | if (fileBlocks[channel].blockNumber != expectingBlock) { |
pvaibhav | 0:ab775bf55fe4 | 163 | DEBUG("Channel %d ok but expected blk %d, not %d!\r\n", channel, expectingBlock, fileBlocks[channel].blockNumber); |
pvaibhav | 0:ab775bf55fe4 | 164 | requestBlock(expectingBlock); |
pvaibhav | 0:ab775bf55fe4 | 165 | return; |
pvaibhav | 0:ab775bf55fe4 | 166 | } else { |
pvaibhav | 0:ab775bf55fe4 | 167 | // DEBUG("."); // one dot = one successfully received packet |
pvaibhav | 0:ab775bf55fe4 | 168 | } |
pvaibhav | 0:ab775bf55fe4 | 169 | |
pvaibhav | 0:ab775bf55fe4 | 170 | if (fileBlocks[channel].blockNumber > (fileInfo.length / Config::blockSize)) { |
pvaibhav | 0:ab775bf55fe4 | 171 | DEBUG("Error: block %d is out of range\r\n", fileBlocks[channel].blockNumber); |
pvaibhav | 0:ab775bf55fe4 | 172 | return; |
pvaibhav | 0:ab775bf55fe4 | 173 | } |
pvaibhav | 0:ab775bf55fe4 | 174 | |
pvaibhav | 0:ab775bf55fe4 | 175 | // "processing" step disabled |
pvaibhav | 0:ab775bf55fe4 | 176 | //uint16_t offset = fileBlock.blockNumber * Config::blockSize; |
pvaibhav | 0:ab775bf55fe4 | 177 | //memcpy(downloadLocation, fileBlock[0].data, Config::blockSize); |
pvaibhav | 0:ab775bf55fe4 | 178 | |
pvaibhav | 0:ab775bf55fe4 | 179 | // request next block if needed |
pvaibhav | 0:ab775bf55fe4 | 180 | uint16_t nextBlock = fileBlocks[channel].blockNumber + 1; |
pvaibhav | 0:ab775bf55fe4 | 181 | if (nextBlock <= fileInfo.length / Config::blockSize) |
pvaibhav | 0:ab775bf55fe4 | 182 | requestBlock(nextBlock); |
pvaibhav | 0:ab775bf55fe4 | 183 | else { |
pvaibhav | 0:ab775bf55fe4 | 184 | sendFileDownloadedSuccessfully(); |
pvaibhav | 0:ab775bf55fe4 | 185 | } |
pvaibhav | 0:ab775bf55fe4 | 186 | } else { |
pvaibhav | 0:ab775bf55fe4 | 187 | DEBUG("Got data on ch %d, but expected on ch %d!\r\n", handle - 1, channel); |
pvaibhav | 0:ab775bf55fe4 | 188 | } |
pvaibhav | 0:ab775bf55fe4 | 189 | } |
pvaibhav | 0:ab775bf55fe4 | 190 | |
pvaibhav | 0:ab775bf55fe4 | 191 | void requestBlock(uint16_t blockNumber) |
pvaibhav | 0:ab775bf55fe4 | 192 | { |
pvaibhav | 0:ab775bf55fe4 | 193 | // Requesting a block by sending notification is disabled for speed |
pvaibhav | 0:ab775bf55fe4 | 194 | //ble->updateCharacteristicValue(transferFileBlocks[0].getHandle(), (uint8_t*) &blockNumber, sizeof(blockNumber), false); |
pvaibhav | 0:ab775bf55fe4 | 195 | //DEBUG("BlockReq %d --> PHONE\r\n", blockNumber); |
pvaibhav | 0:ab775bf55fe4 | 196 | expectingBlock = blockNumber; |
pvaibhav | 0:ab775bf55fe4 | 197 | } |
pvaibhav | 0:ab775bf55fe4 | 198 | |
pvaibhav | 0:ab775bf55fe4 | 199 | void sendFileInfo(uint32_t value) |
pvaibhav | 0:ab775bf55fe4 | 200 | { |
pvaibhav | 0:ab775bf55fe4 | 201 | // refusal is indicated by sending a fileInfo with all zeros |
pvaibhav | 0:ab775bf55fe4 | 202 | ble->updateCharacteristicValue(transferFileInfo.getHandle(), (uint8_t*) &value, sizeof(value), false); |
pvaibhav | 0:ab775bf55fe4 | 203 | } |
pvaibhav | 0:ab775bf55fe4 | 204 | |
pvaibhav | 0:ab775bf55fe4 | 205 | void refuseFile() |
pvaibhav | 0:ab775bf55fe4 | 206 | { |
pvaibhav | 0:ab775bf55fe4 | 207 | sendFileInfo(0); |
pvaibhav | 0:ab775bf55fe4 | 208 | } |
pvaibhav | 0:ab775bf55fe4 | 209 | |
pvaibhav | 0:ab775bf55fe4 | 210 | void sendFileDownloadedSuccessfully() |
pvaibhav | 0:ab775bf55fe4 | 211 | { |
pvaibhav | 0:ab775bf55fe4 | 212 | sendFileInfo(1); |
pvaibhav | 0:ab775bf55fe4 | 213 | downloadInProgress = false; |
pvaibhav | 0:ab775bf55fe4 | 214 | downloadTimer.stop(); |
pvaibhav | 0:ab775bf55fe4 | 215 | DEBUG("File transfer took %0.1f sec\r\n", downloadTimer.read()); |
pvaibhav | 0:ab775bf55fe4 | 216 | } |
pvaibhav | 0:ab775bf55fe4 | 217 | |
pvaibhav | 0:ab775bf55fe4 | 218 | } // namespace transfer |