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
- Committer:
- pvaibhav
- Date:
- 2014-08-14
- Revision:
- 0:ab775bf55fe4
File content as of revision 0:ab775bf55fe4:
#include "TransferService.h" #include "Logger.h" #include "Configuration.h" namespace Transfer { // Transfer base UUID: ADC710C2-xxxx-4BF5-8244-3CEAAA0F87F5 #define transfer_UUID(x) { 0xAD, 0xC7, 0x10, 0xC2, (((x) & 0xFF00) >> 8), ((x) & 0xFF), 0x4B, 0xF5, 0x82, 0x44, 0x3C, 0xEA, 0xAA, 0x0F, 0x87, 0xF5 } // UUID byte arrays static const uint8_t transferServiceUUID[] = transfer_UUID(0xACDC); static const uint8_t transferFileInfoUUID[] = transfer_UUID(0xACDF); static const uint8_t transferFileBlocksUUID[6][16] = { transfer_UUID(0xACE0), transfer_UUID(0xACE1), transfer_UUID(0xACE2), transfer_UUID(0xACE3), transfer_UUID(0xACE4), transfer_UUID(0xACE5), }; // UUID objects used to initialise Bluetooth API static UUID transferServiceUUID_ = UUID(transferServiceUUID); static UUID transferFileInfoUUID_ = UUID(transferFileInfoUUID); static UUID transferFileBlocksUUID_[6] = { UUID(transferFileBlocksUUID[0]), UUID(transferFileBlocksUUID[1]), UUID(transferFileBlocksUUID[2]), UUID(transferFileBlocksUUID[3]), UUID(transferFileBlocksUUID[4]), UUID(transferFileBlocksUUID[5]), }; // Storage for the value of the characteristics struct fileInfo_t { uint16_t length; uint16_t crc16; }; static struct fileInfo_t fileInfo; struct fileBlock_t { uint16_t blockNumber; uint8_t data[16]; }; static struct fileBlock_t fileBlocks[6]; // 6 blocks // Other things needed for operation static BLEDevice* ble; static Timer downloadTimer; static uint16_t expectingBlock = 0; static bool acceptFile = true; // additional condition whether to accept a file upload or not, currently always accept static bool downloadInProgress = false; // indicates if we are downloading a file from the phone static GattCharacteristic transferFileInfo(transferFileInfoUUID_, (uint8_t*) &fileInfo, sizeof(fileInfo), sizeof(fileInfo), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); static uint8_t fileBlockProperties = GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE; static GattCharacteristic transferFileBlocks[6] = { GattCharacteristic(transferFileBlocksUUID_[0], (uint8_t*) &fileBlocks[0], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), GattCharacteristic(transferFileBlocksUUID_[1], (uint8_t*) &fileBlocks[1], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), GattCharacteristic(transferFileBlocksUUID_[2], (uint8_t*) &fileBlocks[2], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), GattCharacteristic(transferFileBlocksUUID_[3], (uint8_t*) &fileBlocks[3], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), GattCharacteristic(transferFileBlocksUUID_[4], (uint8_t*) &fileBlocks[4], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), GattCharacteristic(transferFileBlocksUUID_[5], (uint8_t*) &fileBlocks[5], sizeof(fileBlock_t), sizeof(fileBlock_t), fileBlockProperties), }; static GattCharacteristic* allChars[] = { &transferFileInfo, &transferFileBlocks[0], &transferFileBlocks[1], &transferFileBlocks[2], &transferFileBlocks[3], &transferFileBlocks[4], &transferFileBlocks[5], }; static GattService transferService(transferServiceUUID_, allChars, sizeof(allChars) / sizeof(GattCharacteristic*)); void init(BLEDevice &bleDevice) { downloadInProgress = false; ble = &bleDevice; ble->addService(transferService); DEBUG("Added transfer service\r\n"); } void reset() { // reset internal state on new connection downloadInProgress = false; } const uint8_t* getServiceUUIDp() { return transferServiceUUID; } void requestBlock(uint16_t); // prototype declaration void sendFileInfo(); void refuseFile(); void sendFileDownloadedSuccessfully(); void handleDataWritten(uint16_t handle) { if (!ble) return; int channel = expectingBlock % 6; if (handle == transferFileInfo.getHandle()) { uint16_t len = sizeof(fileInfo); ble->readCharacteristicValue(handle, (uint8_t*) &fileInfo, &len); if (fileInfo.length == 0 && fileInfo.crc16 == 0) { // signal to cancel pending upload downloadInProgress = false; downloadTimer.reset(); expectingBlock = 0; DEBUG("Download RESET\r\n"); return; } DEBUG("Offered file len=%d, crc=0x%04x, acceptFile=%d, downloadInProgress=%d\r\n", fileInfo.length, fileInfo.crc16, acceptFile, downloadInProgress); // Now we must decide whether to accept it or not if (acceptFile && !downloadInProgress) { downloadTimer.reset(); downloadTimer.start(); downloadInProgress = true; requestBlock(0); } else refuseFile(); } else if (handle == transferFileBlocks[channel].getHandle()) { uint16_t len = sizeof(fileBlocks[channel]); ble->readCharacteristicValue(handle, (uint8_t*) &fileBlocks[channel], &len); //DEBUG("blk %d on ch %d (total %d)", fileBlocks[channel].blockNumber, channel, ++blk) //DEBUG("."); /* uint8_t byte; for (int i = 2; i < len; i++) { byte = *(((uint8_t*) &fileBlock) + i); DEBUG("%c", byte, byte); } */ if (fileBlocks[channel].blockNumber != expectingBlock) { DEBUG("Channel %d ok but expected blk %d, not %d!\r\n", channel, expectingBlock, fileBlocks[channel].blockNumber); requestBlock(expectingBlock); return; } else { // DEBUG("."); // one dot = one successfully received packet } if (fileBlocks[channel].blockNumber > (fileInfo.length / Config::blockSize)) { DEBUG("Error: block %d is out of range\r\n", fileBlocks[channel].blockNumber); return; } // "processing" step disabled //uint16_t offset = fileBlock.blockNumber * Config::blockSize; //memcpy(downloadLocation, fileBlock[0].data, Config::blockSize); // request next block if needed uint16_t nextBlock = fileBlocks[channel].blockNumber + 1; if (nextBlock <= fileInfo.length / Config::blockSize) requestBlock(nextBlock); else { sendFileDownloadedSuccessfully(); } } else { DEBUG("Got data on ch %d, but expected on ch %d!\r\n", handle - 1, channel); } } void requestBlock(uint16_t blockNumber) { // Requesting a block by sending notification is disabled for speed //ble->updateCharacteristicValue(transferFileBlocks[0].getHandle(), (uint8_t*) &blockNumber, sizeof(blockNumber), false); //DEBUG("BlockReq %d --> PHONE\r\n", blockNumber); expectingBlock = blockNumber; } void sendFileInfo(uint32_t value) { // refusal is indicated by sending a fileInfo with all zeros ble->updateCharacteristicValue(transferFileInfo.getHandle(), (uint8_t*) &value, sizeof(value), false); } void refuseFile() { sendFileInfo(0); } void sendFileDownloadedSuccessfully() { sendFileInfo(1); downloadInProgress = false; downloadTimer.stop(); DEBUG("File transfer took %0.1f sec\r\n", downloadTimer.read()); } } // namespace transfer