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-11-05
- Revision:
- 4:29ae814ca55e
- Parent:
- 3:d58f3a5bd66c
- Child:
- 5:90b73268e270
File content as of revision 4:29ae814ca55e:
#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