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 nRF51822
Fork of Puck by
Puck.h
- Committer:
- sigveseb
- Date:
- 2014-07-29
- Revision:
- 9:ba0527c6b6d0
- Parent:
- 7:c07c01c2a741
- Child:
- 10:67e4694f2d74
File content as of revision 9:ba0527c6b6d0:
#ifndef __PUCK_HPP__
#define __PUCK_HPP__
#include "BLEDevice.h"
#include <vector>
#include "Log.h"
enum PuckState {
CONNECTING,
CONNECTED,
ADVERTISING,
DISCONNECTED
};
const UUID stringToUUID(const char* str);
typedef void (*CharacteristicWriteCallback)(uint8_t* value);
typedef struct {
const UUID* uuid;
std::vector<CharacteristicWriteCallback>* callbacks;
} CharacteristicWriteCallbacks;
class Puck {
private:
Puck() {}
Puck(const Puck&);
Puck& operator=(const Puck&);
BLEDevice ble;
uint8_t beaconPayload[25];
PuckState state;
std::vector<GattService*> services;
std::vector<GattCharacteristic*> characteristics;
std::vector<CharacteristicWriteCallbacks*> writeCallbacks;
std::vector<CharacteristicWriteCallback> pendingCallbackStack;
std::vector<uint8_t*> pendingCallbackParameterStack;
GattCharacteristic **previousCharacteristics;
public:
static Puck &getPuck();
BLEDevice &getBle() { return ble; }
PuckState getState() { return state; }
void setState(PuckState state);
void init(uint16_t minor);
void startAdvertising();
void stopAdvertising();
void disconnect();
bool drive();
int countFreeMemory();
void onDataWritten(uint16_t handle);
void addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties = 0xA);
void onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback);
uint8_t* getCharacteristicValue(const UUID uuid);
};
Puck &Puck::getPuck() {
static Puck _puckSingletonInstance;
return _puckSingletonInstance;
}
void onDisconnection(void) {
LOG_INFO("Disconnected.\n");
Puck::getPuck().setState(DISCONNECTED);
}
void onConnection(void) {
LOG_INFO("Connected.\n");
Puck::getPuck().setState(CONNECTED);
}
void onDataWrittenCallback(uint16_t handle) {
Puck::getPuck().onDataWritten(handle);
}
bool isEqualUUID(const UUID* uuidA, const UUID uuidB) {
const uint8_t* uuidABase = uuidA->getBaseUUID();
const uint8_t* uuidBBase = uuidB.getBaseUUID();
for(int i = 0; i < 16; i++) {
if(uuidABase[i] != uuidBBase[i]) {
return false;
}
}
if(uuidA->getShortUUID() != uuidB.getShortUUID()) {
return false;
}
return true;
}
const UUID stringToUUID(const char* str) {
uint8_t array[16];
for(int i = 0; i < 16; i++) {
array[i] = str[i];
}
return UUID(array);
}
void Puck::disconnect() {
ble.disconnect();
}
int Puck::countFreeMemory() {
int blocksize = 256;
int amount = 0;
while (blocksize > 0) {
amount += blocksize;
LOG_VERBOSE("Trying to malloc %i bytes... ", amount);
char *p = (char *) malloc(amount);
if (p == NULL) {
LOG_VERBOSE("FAIL!\n", amount);
amount -= blocksize;
blocksize /= 2;
} else {
free(p);
LOG_VERBOSE("OK!\n", amount);
}
}
LOG_DEBUG("Free memory: %i bytes.\n", amount);
return amount;
}
void Puck::setState(PuckState state) {
LOG_DEBUG("Changed state to %i\n", state);
this->state = state;
}
void Puck::init(uint16_t minor) {
/*
* The Beacon payload (encapsulated within the MSD advertising data structure)
* has the following composition:
* 128-Bit UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
* Major/Minor = 1337 / XXXX
* Tx Power = C8
*/
uint8_t beaconPayloadTemplate[] = {
0x00, 0x00, // Company identifier code (0x004C == Apple)
0x02, // ID
0x15, // length of the remaining payload
0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID
0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61,
0x13, 0x37, // the major value to differenciate a location (Our app requires 1337 as major number)
0x00, 0x00, // the minor value to differenciate a location (Change this to differentiate location pucks)
0xC8 // 2's complement of the Tx power (-56dB)
};
beaconPayloadTemplate[22] = minor >> 8;
beaconPayloadTemplate[23] = minor & 255;
for (int i=0; i < 25; i++) {
beaconPayload[i] = beaconPayloadTemplate[i];
}
ble.init();
LOG_DEBUG("Inited BLEDevice.\n");
setState(DISCONNECTED);
ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
LOG_DEBUG("Accumulate advertising payload: BREDR_NOT_SUPPORTED.\n");
ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, beaconPayload, sizeof(beaconPayload));
LOG_DEBUG("Accumulate advertising payload: beacon data.\n");
ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
LOG_DEBUG("Setting advertising type: ADV_CONNECTABLE_UNDIRECTED.\n");
int hundredMillisecondsInAdvertisingIntervalFormat = 160;
ble.setAdvertisingInterval(hundredMillisecondsInAdvertisingIntervalFormat);
LOG_DEBUG("Set advertising interval: 160 (100 ms).\n");
ble.onDisconnection(onDisconnection);
ble.onConnection(onConnection);
ble.onDataWritten(onDataWrittenCallback);
LOG_DEBUG("Hooked up internal event handlers.\n");
for(int i = 0; i < services.size(); i++) {
ble.addService(*services[i]);
LOG_DEBUG("Added service %x to BLEDevice\n", services[i]);
}
LOG_INFO("Inited puck as 0x%X.\n", minor);
}
void Puck::startAdvertising() {
ble.startAdvertising();
LOG_INFO("Starting to advertise.\n");
setState(ADVERTISING);
}
void Puck::stopAdvertising() {
if(state == ADVERTISING) {
ble.stopAdvertising();
LOG_INFO("Stopped advertising.\n");
setState(DISCONNECTED);
} else {
LOG_WARN("Tried to stop advertising, but advertising is already stopped!\n");
}
}
void Puck::addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties) {
MBED_ASSERT(bytes <= 20);
uint16_t size = sizeof(uint8_t) * bytes;
uint8_t* value = (uint8_t*) malloc(size);
if(value == NULL) {
LOG_ERROR("Unable to malloc value for characteristic. Possibly out of memory!\n");
}
GattCharacteristic* characteristic = new GattCharacteristic(characteristicUuid, value, size, size, properties);
characteristics.push_back(characteristic);
GattService* service = NULL;
int removeIndex = -1;
for(int i = 0; i < services.size(); i++) {
if(isEqualUUID(&services[i]->getUUID(), serviceUuid)) {
service = services[i];
removeIndex = i;
break;
}
}
GattCharacteristic** characteristics = NULL;
int characteristicsLength = 0;
if(service != NULL) {
characteristicsLength = service->getCharacteristicCount() + 1;
characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
if(characteristics == NULL) {
LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
}
for(int i = 0; i < characteristicsLength; i++) {
characteristics[i] = service->getCharacteristic(i);
}
services.erase(services.begin() + removeIndex);
delete service;
free(previousCharacteristics);
} else {
characteristicsLength = 1;
characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
if(characteristics == NULL) {
LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
}
}
characteristics[characteristicsLength - 1] = characteristic;
previousCharacteristics = characteristics;
service = new GattService(serviceUuid, characteristics, characteristicsLength);
services.push_back(service);
LOG_DEBUG("Added characteristic.\n");
}
bool Puck::drive() {
ble.waitForEvent();
if(state == DISCONNECTED) {
startAdvertising();
}
while(pendingCallbackStack.size() > 0) {
pendingCallbackStack.back()(pendingCallbackParameterStack.back());
pendingCallbackStack.pop_back();
pendingCallbackParameterStack.pop_back();
}
return true;
}
void Puck::onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback) {
CharacteristicWriteCallbacks* cb = NULL;
for(int i = 0; i< writeCallbacks.size(); i++) {
if(isEqualUUID(writeCallbacks[i]->uuid, *uuid)) {
cb = writeCallbacks[i];
break;
}
}
if(cb == NULL) {
cb = (CharacteristicWriteCallbacks*) malloc(sizeof(CharacteristicWriteCallbacks));
if(cb == NULL) {
LOG_ERROR("Could not malloc CharacteristicWriteCallbacks container. Possibly out of memory!\n");
}
cb->uuid = uuid;
cb->callbacks = new std::vector<CharacteristicWriteCallback>();
writeCallbacks.push_back(cb);
}
cb->callbacks->push_back(callback);
LOG_VERBOSE("Bound characteristic write callback (uuid: %x, callback: %x)\n", uuid, callback);
}
uint8_t* Puck::getCharacteristicValue(const UUID uuid) {
LOG_VERBOSE("Reading characteristic value for UUID %x\n", uuid);
for(int i = 0; i < characteristics.size(); i++) {
GattCharacteristic* characteristic = characteristics[i];
if(isEqualUUID(&characteristic->getUUID(), uuid)) {
return characteristic->getValuePtr();
}
}
LOG_WARN("Tried to read an unknown characteristic!");
return NULL;
}
void Puck::onDataWritten(uint16_t handle) {
for (int i = 0; i < characteristics.size(); i++) {
GattCharacteristic* characteristic = characteristics[i];
if (characteristic->getHandle() == handle) {
uint16_t maxLength = characteristic->getMaxLength();
ble.readCharacteristicValue(handle, characteristic->getValuePtr(), &maxLength);
for(int j = 0; j < writeCallbacks.size(); j++) {
CharacteristicWriteCallbacks* characteristicWriteCallbacks = writeCallbacks[j];
if(isEqualUUID(characteristicWriteCallbacks->uuid, characteristic->getUUID())) {
for(int k = 0; k < characteristicWriteCallbacks->callbacks->size(); k++) {
pendingCallbackStack.push_back(characteristicWriteCallbacks->callbacks->at(k));
pendingCallbackParameterStack.push_back(characteristic->getValuePtr());
}
return;
}
}
}
}
}
#endif // __PUCK_HPP__
