Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822
TransferService.cpp
- Committer:
- rgrover1
- Date:
- 2014-08-18
- Revision:
- 0:4eaf82806f06
- Child:
- 1:d623a5792ce5
File content as of revision 0:4eaf82806f06:
#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
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 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 requestBlock(uint16_t); // prototype declaration
void sendFileInfo();
void refuseFile();
void sendFileDownloadedSuccessfully();
void handleDataWritten(uint16_t handle)
{
if (!ble) {
return;
}
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 == transferFileBlock.getHandle()) {
uint16_t len = sizeof(fileBlock);
ble->readCharacteristicValue(handle, (uint8_t *) &fileBlock, &len);
// DEBUG("received blk %u (total %u): ", fileBlock.blockNumber, fileInfo.length / Config::blockSize);
// uint8_t byte;
// for (int i = 2; i < len; i++) {
// byte = *(((uint8_t*) &fileBlock) + i);
// DEBUG("%02x ", byte);
// }
// DEBUG("\r\n");
if (fileBlock.blockNumber != expectingBlock) {
DEBUG("Expected blk %d, not %d!\r\n", expectingBlock, fileBlock.blockNumber);
requestBlock(expectingBlock);
return;
} else {
// DEBUG("."); // one dot = one successfully received packet
}
if (fileBlock.blockNumber > (fileInfo.length / Config::blockSize)) {
DEBUG("Error: block %d is out of range\r\n", fileBlock.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 = fileBlock.blockNumber + 1;
if (nextBlock <= fileInfo.length / Config::blockSize) {
requestBlock(nextBlock);
} else {
sendFileDownloadedSuccessfully();
}
} else {
DEBUG("Got data on unexpected characteristic handle %u!\r\n", handle);
}
}
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