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:
Tue Sep 02 16:30:18 2014 +0000
Revision:
3:d58f3a5bd66c
Parent:
2:4ca946e0ebdc
Child:
4:29ae814ca55e
updating underlying libraries.

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 3:d58f3a5bd66c 15 typedef struct {
rgrover1 0:4eaf82806f06 16 uint16_t length;
rgrover1 0:4eaf82806f06 17 uint16_t crc16;
rgrover1 3:d58f3a5bd66c 18 } FileInfo_t;
rgrover1 3:d58f3a5bd66c 19 static FileInfo_t fileInfo;
rgrover1 3:d58f3a5bd66c 20 typedef struct {
rgrover1 0:4eaf82806f06 21 uint16_t blockNumber;
rgrover1 0:4eaf82806f06 22 uint8_t data[16];
rgrover1 3:d58f3a5bd66c 23 } FileBlock_t;
rgrover1 3:d58f3a5bd66c 24 static FileBlock_t fileBlock;
rgrover1 0:4eaf82806f06 25
rgrover1 0:4eaf82806f06 26 // Other things needed for operation
rgrover1 3:d58f3a5bd66c 27 static BLEDevice* ble;
rgrover1 3:d58f3a5bd66c 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 3:d58f3a5bd66c 43 sizeof(FileBlock_t),
rgrover1 3:d58f3a5bd66c 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 3:d58f3a5bd66c 74 void handleDataWritten(uint16_t handle, const GattCharacteristicWriteCBParams *params)
rgrover1 0:4eaf82806f06 75 {
rgrover1 0:4eaf82806f06 76 if (!ble) {
rgrover1 0:4eaf82806f06 77 return;
rgrover1 0:4eaf82806f06 78 }
rgrover1 0:4eaf82806f06 79
carlescufi 2:4ca946e0ebdc 80 if (handle == transferFileInfo.getValueAttribute().getHandle()) {
rgrover1 3:d58f3a5bd66c 81 if (params->len != sizeof(FileInfo_t)) {
rgrover1 3:d58f3a5bd66c 82 DEBUG("invalid write into fileInfo characteristic\r\n");
rgrover1 3:d58f3a5bd66c 83 return;
rgrover1 3:d58f3a5bd66c 84 }
rgrover1 3:d58f3a5bd66c 85 memcpy(&fileInfo, params->data, params->len);
rgrover1 0:4eaf82806f06 86
rgrover1 0:4eaf82806f06 87 if ((fileInfo.length == 0) && (fileInfo.crc16 == 0)) {
rgrover1 0:4eaf82806f06 88 // signal to cancel pending upload
rgrover1 0:4eaf82806f06 89 downloadInProgress = false;
rgrover1 0:4eaf82806f06 90 downloadTimer.reset();
rgrover1 0:4eaf82806f06 91 expectingBlock = 0;
rgrover1 0:4eaf82806f06 92 DEBUG("Download RESET\r\n");
rgrover1 0:4eaf82806f06 93 return;
rgrover1 0:4eaf82806f06 94 }
rgrover1 0:4eaf82806f06 95
rgrover1 1:d623a5792ce5 96 DEBUG("Offered file len=%u, crc=0x%04x, acceptFile=%u, downloadInProgress=%u\r\n",
rgrover1 1:d623a5792ce5 97 fileInfo.length, fileInfo.crc16, acceptFile, downloadInProgress);
rgrover1 0:4eaf82806f06 98
rgrover1 0:4eaf82806f06 99 // Now we must decide whether to accept it or not
rgrover1 0:4eaf82806f06 100 if (acceptFile && !downloadInProgress) {
rgrover1 0:4eaf82806f06 101 downloadTimer.reset();
rgrover1 0:4eaf82806f06 102 downloadTimer.start();
rgrover1 0:4eaf82806f06 103 downloadInProgress = true;
rgrover1 1:d623a5792ce5 104 expectingBlock = 0;
rgrover1 0:4eaf82806f06 105 } else {
rgrover1 0:4eaf82806f06 106 refuseFile();
rgrover1 0:4eaf82806f06 107 }
carlescufi 2:4ca946e0ebdc 108 } else if (handle == transferFileBlock.getValueAttribute().getHandle()) {
rgrover1 3:d58f3a5bd66c 109 if (params->len != sizeof(FileBlock_t)) {
rgrover1 3:d58f3a5bd66c 110 DEBUG("invalid write into fileInfo characteristic\r\n");
rgrover1 3:d58f3a5bd66c 111 return;
rgrover1 3:d58f3a5bd66c 112 }
rgrover1 3:d58f3a5bd66c 113 memcpy(&fileBlock, params->data, params->len);
rgrover1 0:4eaf82806f06 114
rgrover1 0:4eaf82806f06 115 if (fileBlock.blockNumber != expectingBlock) {
rgrover1 1:d623a5792ce5 116 DEBUG("Expected blk %u, not %u!\r\n", expectingBlock, fileBlock.blockNumber);
rgrover1 1:d623a5792ce5 117 } else if (fileBlock.blockNumber <= (fileInfo.length / Config::blockSize)) {
rgrover1 1:d623a5792ce5 118 expectingBlock = fileBlock.blockNumber + 1;
rgrover1 1:d623a5792ce5 119 if (fileBlock.blockNumber == ((fileInfo.length / Config::blockSize) - 1)) {
rgrover1 1:d623a5792ce5 120 sendFileDownloadedSuccessfully();
rgrover1 1:d623a5792ce5 121 }
rgrover1 0:4eaf82806f06 122 } else {
rgrover1 1:d623a5792ce5 123 DEBUG("Error: block %u is out of range\r\n", fileBlock.blockNumber);
rgrover1 0:4eaf82806f06 124 }
rgrover1 0:4eaf82806f06 125 } else {
rgrover1 0:4eaf82806f06 126 DEBUG("Got data on unexpected characteristic handle %u!\r\n", handle);
rgrover1 0:4eaf82806f06 127 }
rgrover1 0:4eaf82806f06 128 }
rgrover1 0:4eaf82806f06 129
rgrover1 0:4eaf82806f06 130 void sendFileInfo(uint32_t value)
rgrover1 0:4eaf82806f06 131 {
rgrover1 0:4eaf82806f06 132 // refusal is indicated by sending a fileInfo with all zeros
carlescufi 2:4ca946e0ebdc 133 ble->updateCharacteristicValue(transferFileInfo.getValueAttribute().getHandle(), (uint8_t *) &value, sizeof(value), false);
rgrover1 0:4eaf82806f06 134 }
rgrover1 0:4eaf82806f06 135
rgrover1 0:4eaf82806f06 136 void refuseFile()
rgrover1 0:4eaf82806f06 137 {
rgrover1 0:4eaf82806f06 138 sendFileInfo(0);
rgrover1 0:4eaf82806f06 139 }
rgrover1 0:4eaf82806f06 140
rgrover1 0:4eaf82806f06 141 void sendFileDownloadedSuccessfully()
rgrover1 0:4eaf82806f06 142 {
rgrover1 0:4eaf82806f06 143 sendFileInfo(1);
rgrover1 0:4eaf82806f06 144 downloadInProgress = false;
rgrover1 0:4eaf82806f06 145 downloadTimer.stop();
rgrover1 0:4eaf82806f06 146 DEBUG("File transfer took %0.1f sec\r\n", downloadTimer.read());
rgrover1 0:4eaf82806f06 147 }
rgrover1 0:4eaf82806f06 148 } // namespace transfer