Download a stream of data to a peripheral over BLE.
Dependencies: BLE_API mbed nRF51822
A simple demonstration of downloading a stream onto a peripheral over BLE. There's a corresponding Python script to driver the client.
TransferService.cpp
- Committer:
- rgrover1
- Date:
- 2014-12-09
- Revision:
- 5:90b73268e270
- Parent:
- 4:29ae814ca55e
File content as of revision 5:90b73268e270:
#include "mbed.h" #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 transferFileBlockUUID[16] = transfer_UUID(0xACE0); // Storage for the value of the characteristics typedef struct { uint16_t length; uint16_t crc16; } FileInfo_t; static FileInfo_t fileInfo; typedef struct { uint16_t blockNumber; uint8_t data[16]; } FileBlock_t; static FileBlock_t fileBlock; // 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 GattCharacteristic transferFileBlock(transferFileBlockUUID, (uint8_t *)&fileBlock, sizeof(FileBlock_t), sizeof(FileBlock_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); static GattCharacteristic *allChars[] = {&transferFileInfo, &transferFileBlock}; 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 sendFileInfo(); void refuseFile(); void sendFileDownloadedSuccessfully(); void handleDataWritten(const GattCharacteristicWriteCBParams *params) { if (!ble) { return; } if (params->charHandle == transferFileInfo.getValueAttribute().getHandle()) { if (params->len != sizeof(FileInfo_t)) { DEBUG("invalid write into fileInfo characteristic\r\n"); return; } memcpy(&fileInfo, params->data, params->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=%u, crc=0x%04x, acceptFile=%u, downloadInProgress=%u\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; expectingBlock = 0; } else { refuseFile(); } } else if (params->charHandle == transferFileBlock.getValueAttribute().getHandle()) { if (params->len != sizeof(FileBlock_t)) { DEBUG("invalid write into fileInfo characteristic\r\n"); return; } memcpy(&fileBlock, params->data, params->len); if (fileBlock.blockNumber != expectingBlock) { DEBUG("Expected blk %u, not %u!\r\n", expectingBlock, fileBlock.blockNumber); } else if (fileBlock.blockNumber <= (fileInfo.length / Config::blockSize)) { expectingBlock = fileBlock.blockNumber + 1; if (fileBlock.blockNumber == ((fileInfo.length / Config::blockSize) - 1)) { sendFileDownloadedSuccessfully(); } } else { DEBUG("Error: block %u is out of range\r\n", fileBlock.blockNumber); } } else { DEBUG("Got data on unexpected characteristic handle %u!\r\n", params->charHandle); } } void sendFileInfo(uint32_t value) { // refusal is indicated by sending a fileInfo with all zeros ble->updateCharacteristicValue(transferFileInfo.getValueAttribute().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