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.

Committer:
rgrover1
Date:
Thu Aug 21 14:09:18 2014 +0000
Revision:
1:d623a5792ce5
Parent:
0:4eaf82806f06
Child:
2:4ca946e0ebdc
minor cleanup.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 0:4eaf82806f06 1 #include "TransferService.h"
rgrover1 0:4eaf82806f06 2 #include "Logger.h"
rgrover1 0:4eaf82806f06 3 #include "Configuration.h"
rgrover1 0:4eaf82806f06 4
rgrover1 0:4eaf82806f06 5 namespace Transfer {
rgrover1 0:4eaf82806f06 6 // Transfer base UUID: ADC710C2-xxxx-4BF5-8244-3CEAAA0F87F5
rgrover1 0:4eaf82806f06 7 #define transfer_UUID(x) {0xAD, 0xC7, 0x10, 0xC2, (((x) & 0xFF00) >> 8), ((x) & 0xFF), 0x4B, 0xF5, 0x82, 0x44, 0x3C, 0xEA, 0xAA, 0x0F, 0x87, 0xF5}
rgrover1 0:4eaf82806f06 8
rgrover1 0:4eaf82806f06 9 // UUID byte arrays
rgrover1 0:4eaf82806f06 10 static const uint8_t transferServiceUUID[] = transfer_UUID(0xACDC);
rgrover1 0:4eaf82806f06 11 static const uint8_t transferFileInfoUUID[] = transfer_UUID(0xACDF);
rgrover1 0:4eaf82806f06 12 static const uint8_t transferFileBlockUUID[16] = transfer_UUID(0xACE0);
rgrover1 0:4eaf82806f06 13
rgrover1 0:4eaf82806f06 14 // Storage for the value of the characteristics
rgrover1 0:4eaf82806f06 15 struct fileInfo_t {
rgrover1 0:4eaf82806f06 16 uint16_t length;
rgrover1 0:4eaf82806f06 17 uint16_t crc16;
rgrover1 0:4eaf82806f06 18 };
rgrover1 0:4eaf82806f06 19 static struct fileInfo_t fileInfo;
rgrover1 0:4eaf82806f06 20 struct fileBlock_t {
rgrover1 0:4eaf82806f06 21 uint16_t blockNumber;
rgrover1 0:4eaf82806f06 22 uint8_t data[16];
rgrover1 0:4eaf82806f06 23 };
rgrover1 0:4eaf82806f06 24 static struct fileBlock_t fileBlock;
rgrover1 0:4eaf82806f06 25
rgrover1 0:4eaf82806f06 26 // Other things needed for operation
rgrover1 0:4eaf82806f06 27 static BLEDevice* ble;
rgrover1 0:4eaf82806f06 28 static Timer downloadTimer;
rgrover1 0:4eaf82806f06 29
rgrover1 0:4eaf82806f06 30 static uint16_t expectingBlock = 0;
rgrover1 0:4eaf82806f06 31
rgrover1 0:4eaf82806f06 32 static bool acceptFile = true; // additional condition whether to accept a file upload or not, currently always accept
rgrover1 0:4eaf82806f06 33 static bool downloadInProgress = false; // indicates if we are downloading a file from the phone
rgrover1 0:4eaf82806f06 34
rgrover1 0:4eaf82806f06 35 static GattCharacteristic transferFileInfo(transferFileInfoUUID,
rgrover1 0:4eaf82806f06 36 (uint8_t *)&fileInfo,
rgrover1 0:4eaf82806f06 37 sizeof(fileInfo),
rgrover1 0:4eaf82806f06 38 sizeof(fileInfo),
rgrover1 0:4eaf82806f06 39 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
rgrover1 0:4eaf82806f06 40
rgrover1 0:4eaf82806f06 41 static GattCharacteristic transferFileBlock(transferFileBlockUUID,
rgrover1 0:4eaf82806f06 42 (uint8_t *)&fileBlock,
rgrover1 0:4eaf82806f06 43 sizeof(fileBlock_t),
rgrover1 0:4eaf82806f06 44 sizeof(fileBlock_t),
rgrover1 0:4eaf82806f06 45 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
rgrover1 0:4eaf82806f06 46 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
rgrover1 0:4eaf82806f06 47
rgrover1 0:4eaf82806f06 48 static GattCharacteristic *allChars[] = {&transferFileInfo, &transferFileBlock};
rgrover1 0:4eaf82806f06 49 static GattService transferService(transferServiceUUID, allChars, sizeof(allChars) / sizeof(GattCharacteristic *));
rgrover1 0:4eaf82806f06 50
rgrover1 0:4eaf82806f06 51 void init(BLEDevice &bleDevice)
rgrover1 0:4eaf82806f06 52 {
rgrover1 0:4eaf82806f06 53 downloadInProgress = false;
rgrover1 0:4eaf82806f06 54 ble = &bleDevice;
rgrover1 0:4eaf82806f06 55 ble->addService(transferService);
rgrover1 0:4eaf82806f06 56 DEBUG("Added transfer service\r\n");
rgrover1 0:4eaf82806f06 57 }
rgrover1 0:4eaf82806f06 58
rgrover1 0:4eaf82806f06 59 void reset()
rgrover1 0:4eaf82806f06 60 {
rgrover1 0:4eaf82806f06 61 // reset internal state on new connection
rgrover1 0:4eaf82806f06 62 downloadInProgress = false;
rgrover1 0:4eaf82806f06 63 }
rgrover1 0:4eaf82806f06 64
rgrover1 0:4eaf82806f06 65 const uint8_t *getServiceUUIDp()
rgrover1 0:4eaf82806f06 66 {
rgrover1 0:4eaf82806f06 67 return transferServiceUUID;
rgrover1 0:4eaf82806f06 68 }
rgrover1 0:4eaf82806f06 69
rgrover1 0:4eaf82806f06 70 void sendFileInfo();
rgrover1 0:4eaf82806f06 71 void refuseFile();
rgrover1 0:4eaf82806f06 72 void sendFileDownloadedSuccessfully();
rgrover1 0:4eaf82806f06 73
rgrover1 0:4eaf82806f06 74 void handleDataWritten(uint16_t handle)
rgrover1 0:4eaf82806f06 75 {
rgrover1 0:4eaf82806f06 76 if (!ble) {
rgrover1 0:4eaf82806f06 77 return;
rgrover1 0:4eaf82806f06 78 }
rgrover1 0:4eaf82806f06 79
rgrover1 0:4eaf82806f06 80 if (handle == transferFileInfo.getHandle()) {
rgrover1 0:4eaf82806f06 81 uint16_t len = sizeof(fileInfo);
rgrover1 0:4eaf82806f06 82 ble->readCharacteristicValue(handle, (uint8_t *) &fileInfo, &len);
rgrover1 0:4eaf82806f06 83
rgrover1 0:4eaf82806f06 84 if ((fileInfo.length == 0) && (fileInfo.crc16 == 0)) {
rgrover1 0:4eaf82806f06 85 // signal to cancel pending upload
rgrover1 0:4eaf82806f06 86 downloadInProgress = false;
rgrover1 0:4eaf82806f06 87 downloadTimer.reset();
rgrover1 0:4eaf82806f06 88 expectingBlock = 0;
rgrover1 0:4eaf82806f06 89 DEBUG("Download RESET\r\n");
rgrover1 0:4eaf82806f06 90 return;
rgrover1 0:4eaf82806f06 91 }
rgrover1 0:4eaf82806f06 92
rgrover1 1:d623a5792ce5 93 DEBUG("Offered file len=%u, crc=0x%04x, acceptFile=%u, downloadInProgress=%u\r\n",
rgrover1 1:d623a5792ce5 94 fileInfo.length, fileInfo.crc16, acceptFile, downloadInProgress);
rgrover1 0:4eaf82806f06 95
rgrover1 0:4eaf82806f06 96 // Now we must decide whether to accept it or not
rgrover1 0:4eaf82806f06 97 if (acceptFile && !downloadInProgress) {
rgrover1 0:4eaf82806f06 98 downloadTimer.reset();
rgrover1 0:4eaf82806f06 99 downloadTimer.start();
rgrover1 0:4eaf82806f06 100 downloadInProgress = true;
rgrover1 1:d623a5792ce5 101 expectingBlock = 0;
rgrover1 0:4eaf82806f06 102 } else {
rgrover1 0:4eaf82806f06 103 refuseFile();
rgrover1 0:4eaf82806f06 104 }
rgrover1 0:4eaf82806f06 105 } else if (handle == transferFileBlock.getHandle()) {
rgrover1 0:4eaf82806f06 106 uint16_t len = sizeof(fileBlock);
rgrover1 0:4eaf82806f06 107 ble->readCharacteristicValue(handle, (uint8_t *) &fileBlock, &len);
rgrover1 0:4eaf82806f06 108
rgrover1 0:4eaf82806f06 109 if (fileBlock.blockNumber != expectingBlock) {
rgrover1 1:d623a5792ce5 110 DEBUG("Expected blk %u, not %u!\r\n", expectingBlock, fileBlock.blockNumber);
rgrover1 1:d623a5792ce5 111 } else if (fileBlock.blockNumber <= (fileInfo.length / Config::blockSize)) {
rgrover1 1:d623a5792ce5 112 expectingBlock = fileBlock.blockNumber + 1;
rgrover1 1:d623a5792ce5 113 if (fileBlock.blockNumber == ((fileInfo.length / Config::blockSize) - 1)) {
rgrover1 1:d623a5792ce5 114 sendFileDownloadedSuccessfully();
rgrover1 1:d623a5792ce5 115 }
rgrover1 0:4eaf82806f06 116 } else {
rgrover1 1:d623a5792ce5 117 DEBUG("Error: block %u is out of range\r\n", fileBlock.blockNumber);
rgrover1 0:4eaf82806f06 118 }
rgrover1 0:4eaf82806f06 119 } else {
rgrover1 0:4eaf82806f06 120 DEBUG("Got data on unexpected characteristic handle %u!\r\n", handle);
rgrover1 0:4eaf82806f06 121 }
rgrover1 0:4eaf82806f06 122 }
rgrover1 0:4eaf82806f06 123
rgrover1 0:4eaf82806f06 124 void sendFileInfo(uint32_t value)
rgrover1 0:4eaf82806f06 125 {
rgrover1 0:4eaf82806f06 126 // refusal is indicated by sending a fileInfo with all zeros
rgrover1 0:4eaf82806f06 127 ble->updateCharacteristicValue(transferFileInfo.getHandle(), (uint8_t *) &value, sizeof(value), false);
rgrover1 0:4eaf82806f06 128 }
rgrover1 0:4eaf82806f06 129
rgrover1 0:4eaf82806f06 130 void refuseFile()
rgrover1 0:4eaf82806f06 131 {
rgrover1 0:4eaf82806f06 132 sendFileInfo(0);
rgrover1 0:4eaf82806f06 133 }
rgrover1 0:4eaf82806f06 134
rgrover1 0:4eaf82806f06 135 void sendFileDownloadedSuccessfully()
rgrover1 0:4eaf82806f06 136 {
rgrover1 0:4eaf82806f06 137 sendFileInfo(1);
rgrover1 0:4eaf82806f06 138 downloadInProgress = false;
rgrover1 0:4eaf82806f06 139 downloadTimer.stop();
rgrover1 0:4eaf82806f06 140 DEBUG("File transfer took %0.1f sec\r\n", downloadTimer.read());
rgrover1 0:4eaf82806f06 141 }
rgrover1 0:4eaf82806f06 142 } // namespace transfer