Update for latest nRF51822 code changes.

Dependencies:   BLE_API nRF51822

Fork of Puck by Nordic Pucks

Committer:
stiaje
Date:
Fri Aug 01 07:45:38 2014 +0000
Revision:
10:67e4694f2d74
Merge 'Update display puck to use new lib'

Who changed what in which revision?

UserRevisionLine numberNew contents of line
stiaje 10:67e4694f2d74 1 #ifndef __PUCK_HPP__
stiaje 10:67e4694f2d74 2 #define __PUCK_HPP__
stiaje 10:67e4694f2d74 3
stiaje 10:67e4694f2d74 4 #include "BLEDevice.h"
stiaje 10:67e4694f2d74 5 #include <vector>
stiaje 10:67e4694f2d74 6 #include "Log.h"
stiaje 10:67e4694f2d74 7
stiaje 10:67e4694f2d74 8 enum PuckState {
stiaje 10:67e4694f2d74 9 CONNECTING,
stiaje 10:67e4694f2d74 10 CONNECTED,
stiaje 10:67e4694f2d74 11 ADVERTISING,
stiaje 10:67e4694f2d74 12 DISCONNECTED
stiaje 10:67e4694f2d74 13 };
stiaje 10:67e4694f2d74 14
stiaje 10:67e4694f2d74 15 const UUID stringToUUID(const char* str);
stiaje 10:67e4694f2d74 16
stiaje 10:67e4694f2d74 17 typedef void (*CharacteristicWriteCallback)(uint8_t* value);
stiaje 10:67e4694f2d74 18
stiaje 10:67e4694f2d74 19 typedef struct {
stiaje 10:67e4694f2d74 20 const UUID* uuid;
stiaje 10:67e4694f2d74 21 std::vector<CharacteristicWriteCallback>* callbacks;
stiaje 10:67e4694f2d74 22 } CharacteristicWriteCallbacks;
stiaje 10:67e4694f2d74 23
stiaje 10:67e4694f2d74 24
stiaje 10:67e4694f2d74 25 class Puck {
stiaje 10:67e4694f2d74 26 private:
stiaje 10:67e4694f2d74 27 Puck() {}
stiaje 10:67e4694f2d74 28 Puck(const Puck&);
stiaje 10:67e4694f2d74 29 Puck& operator=(const Puck&);
stiaje 10:67e4694f2d74 30
stiaje 10:67e4694f2d74 31 BLEDevice ble;
stiaje 10:67e4694f2d74 32 uint8_t beaconPayload[25];
stiaje 10:67e4694f2d74 33 PuckState state;
stiaje 10:67e4694f2d74 34 std::vector<GattService*> services;
stiaje 10:67e4694f2d74 35 std::vector<GattCharacteristic*> characteristics;
stiaje 10:67e4694f2d74 36 std::vector<CharacteristicWriteCallbacks*> writeCallbacks;
stiaje 10:67e4694f2d74 37 std::vector<CharacteristicWriteCallback> pendingCallbackStack;
stiaje 10:67e4694f2d74 38 std::vector<uint8_t*> pendingCallbackParameterStack;
stiaje 10:67e4694f2d74 39
stiaje 10:67e4694f2d74 40 GattCharacteristic **previousCharacteristics;
stiaje 10:67e4694f2d74 41
stiaje 10:67e4694f2d74 42 public:
stiaje 10:67e4694f2d74 43 static Puck &getPuck();
stiaje 10:67e4694f2d74 44
stiaje 10:67e4694f2d74 45 BLEDevice &getBle() { return ble; }
stiaje 10:67e4694f2d74 46 PuckState getState() { return state; }
stiaje 10:67e4694f2d74 47 void setState(PuckState state);
stiaje 10:67e4694f2d74 48 void init(uint16_t minor);
stiaje 10:67e4694f2d74 49 void startAdvertising();
stiaje 10:67e4694f2d74 50 void stopAdvertising();
stiaje 10:67e4694f2d74 51 bool drive();
stiaje 10:67e4694f2d74 52 void onDataWritten(uint16_t handle);
stiaje 10:67e4694f2d74 53 void addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties = 0xA);
stiaje 10:67e4694f2d74 54 void onCharacteristicWrite(const UUID uuid, CharacteristicWriteCallback callback);
stiaje 10:67e4694f2d74 55 void updateCharacteristicValue(const UUID uuid, uint8_t* value, int length);
stiaje 10:67e4694f2d74 56 uint8_t* getCharacteristicValue(const UUID uuid);
stiaje 10:67e4694f2d74 57 };
stiaje 10:67e4694f2d74 58
stiaje 10:67e4694f2d74 59 Puck &Puck::getPuck() {
stiaje 10:67e4694f2d74 60 static Puck _puckSingletonInstance;
stiaje 10:67e4694f2d74 61 return _puckSingletonInstance;
stiaje 10:67e4694f2d74 62 }
stiaje 10:67e4694f2d74 63
stiaje 10:67e4694f2d74 64
stiaje 10:67e4694f2d74 65 void onDisconnection(void) {
stiaje 10:67e4694f2d74 66 LOG_INFO("Disconnected.\n");
stiaje 10:67e4694f2d74 67 Puck::getPuck().setState(DISCONNECTED);
stiaje 10:67e4694f2d74 68 }
stiaje 10:67e4694f2d74 69
stiaje 10:67e4694f2d74 70 void onConnection(void) {
stiaje 10:67e4694f2d74 71 LOG_INFO("Connected.\n");
stiaje 10:67e4694f2d74 72 Puck::getPuck().setState(CONNECTED);
stiaje 10:67e4694f2d74 73 }
stiaje 10:67e4694f2d74 74
stiaje 10:67e4694f2d74 75 void onDataWrittenCallback(uint16_t handle) {
stiaje 10:67e4694f2d74 76 Puck::getPuck().onDataWritten(handle);
stiaje 10:67e4694f2d74 77 }
stiaje 10:67e4694f2d74 78
stiaje 10:67e4694f2d74 79 bool isEqualUUID(const UUID* uuidA, const UUID uuidB) {
stiaje 10:67e4694f2d74 80 const uint8_t* uuidABase = uuidA->getBaseUUID();
stiaje 10:67e4694f2d74 81 const uint8_t* uuidBBase = uuidB.getBaseUUID();
stiaje 10:67e4694f2d74 82 if(uuidA->getShortUUID() != uuidB.getShortUUID()) {
stiaje 10:67e4694f2d74 83 return false;
stiaje 10:67e4694f2d74 84 }
stiaje 10:67e4694f2d74 85 for(int i = 0; i < 16; i++) {
stiaje 10:67e4694f2d74 86 if(uuidABase[i] != uuidBBase[i]) {
stiaje 10:67e4694f2d74 87 return false;
stiaje 10:67e4694f2d74 88 }
stiaje 10:67e4694f2d74 89 }
stiaje 10:67e4694f2d74 90 return true;
stiaje 10:67e4694f2d74 91 }
stiaje 10:67e4694f2d74 92
stiaje 10:67e4694f2d74 93 const UUID stringToUUID(const char* str) {
stiaje 10:67e4694f2d74 94 uint8_t array[16];
stiaje 10:67e4694f2d74 95 for(int i = 0; i < 16; i++) {
stiaje 10:67e4694f2d74 96 array[i] = str[i];
stiaje 10:67e4694f2d74 97 }
stiaje 10:67e4694f2d74 98 return UUID(array);
stiaje 10:67e4694f2d74 99 }
stiaje 10:67e4694f2d74 100
stiaje 10:67e4694f2d74 101 void Puck::setState(PuckState state) {
stiaje 10:67e4694f2d74 102 LOG_DEBUG("Changed state to %i\n", state);
stiaje 10:67e4694f2d74 103 this->state = state;
stiaje 10:67e4694f2d74 104 }
stiaje 10:67e4694f2d74 105
stiaje 10:67e4694f2d74 106 void Puck::init(uint16_t minor) {
stiaje 10:67e4694f2d74 107 /*
stiaje 10:67e4694f2d74 108 * The Beacon payload (encapsulated within the MSD advertising data structure)
stiaje 10:67e4694f2d74 109 * has the following composition:
stiaje 10:67e4694f2d74 110 * 128-Bit UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
stiaje 10:67e4694f2d74 111 * Major/Minor = 1337 / XXXX
stiaje 10:67e4694f2d74 112 * Tx Power = C8
stiaje 10:67e4694f2d74 113 */
stiaje 10:67e4694f2d74 114 uint8_t beaconPayloadTemplate[] = {
stiaje 10:67e4694f2d74 115 0x00, 0x00, // Company identifier code (0x004C == Apple)
stiaje 10:67e4694f2d74 116 0x02, // ID
stiaje 10:67e4694f2d74 117 0x15, // length of the remaining payload
stiaje 10:67e4694f2d74 118 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID
stiaje 10:67e4694f2d74 119 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61,
stiaje 10:67e4694f2d74 120 0x13, 0x37, // the major value to differenciate a location (Our app requires 1337 as major number)
stiaje 10:67e4694f2d74 121 0x00, 0x00, // the minor value to differenciate a location (Change this to differentiate location pucks)
stiaje 10:67e4694f2d74 122 0xC8 // 2's complement of the Tx power (-56dB)
stiaje 10:67e4694f2d74 123 };
stiaje 10:67e4694f2d74 124 beaconPayloadTemplate[22] = minor >> 8;
stiaje 10:67e4694f2d74 125 beaconPayloadTemplate[23] = minor & 255;
stiaje 10:67e4694f2d74 126
stiaje 10:67e4694f2d74 127 for (int i=0; i < 25; i++) {
stiaje 10:67e4694f2d74 128 beaconPayload[i] = beaconPayloadTemplate[i];
stiaje 10:67e4694f2d74 129 }
stiaje 10:67e4694f2d74 130
stiaje 10:67e4694f2d74 131 ble.init();
stiaje 10:67e4694f2d74 132 LOG_VERBOSE("Inited BLEDevice.\n");
stiaje 10:67e4694f2d74 133 setState(DISCONNECTED);
stiaje 10:67e4694f2d74 134
stiaje 10:67e4694f2d74 135 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
stiaje 10:67e4694f2d74 136 LOG_VERBOSE("Accumulate advertising payload: BREDR_NOT_SUPPORTED.\n");
stiaje 10:67e4694f2d74 137
stiaje 10:67e4694f2d74 138 ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, beaconPayload, sizeof(beaconPayload));
stiaje 10:67e4694f2d74 139 LOG_VERBOSE("Accumulate advertising payload: beacon data.\n");
stiaje 10:67e4694f2d74 140
stiaje 10:67e4694f2d74 141 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
stiaje 10:67e4694f2d74 142 LOG_VERBOSE("Setting advertising type: ADV_CONNECTABLE_UNDIRECTED.\n");
stiaje 10:67e4694f2d74 143
stiaje 10:67e4694f2d74 144 int hundredMillisecondsInAdvertisingIntervalFormat = 160;
stiaje 10:67e4694f2d74 145 ble.setAdvertisingInterval(hundredMillisecondsInAdvertisingIntervalFormat);
stiaje 10:67e4694f2d74 146 LOG_VERBOSE("Set advertising interval: 160 (100 ms).\n");
stiaje 10:67e4694f2d74 147
stiaje 10:67e4694f2d74 148 ble.onDisconnection(onDisconnection);
stiaje 10:67e4694f2d74 149 ble.onConnection(onConnection);
stiaje 10:67e4694f2d74 150 ble.onDataWritten(onDataWrittenCallback);
stiaje 10:67e4694f2d74 151
stiaje 10:67e4694f2d74 152 for(int i = 0; i < services.size(); i++) {
stiaje 10:67e4694f2d74 153 ble.addService(*services[i]);
stiaje 10:67e4694f2d74 154 LOG_VERBOSE("Added service %x to BLEDevice\n", services[i]);
stiaje 10:67e4694f2d74 155 }
stiaje 10:67e4694f2d74 156
stiaje 10:67e4694f2d74 157 LOG_INFO("Inited puck as 0x%X.\n", minor);
stiaje 10:67e4694f2d74 158 }
stiaje 10:67e4694f2d74 159
stiaje 10:67e4694f2d74 160 void Puck::startAdvertising() {
stiaje 10:67e4694f2d74 161 ble.startAdvertising();
stiaje 10:67e4694f2d74 162 LOG_INFO("Starting to advertise.\n");
stiaje 10:67e4694f2d74 163 setState(ADVERTISING);
stiaje 10:67e4694f2d74 164 }
stiaje 10:67e4694f2d74 165
stiaje 10:67e4694f2d74 166 void Puck::stopAdvertising() {
stiaje 10:67e4694f2d74 167 if(state == ADVERTISING) {
stiaje 10:67e4694f2d74 168 ble.stopAdvertising();
stiaje 10:67e4694f2d74 169 LOG_INFO("Stopped advertising.\n");
stiaje 10:67e4694f2d74 170 setState(DISCONNECTED);
stiaje 10:67e4694f2d74 171 } else {
stiaje 10:67e4694f2d74 172 LOG_WARN("Tried to stop advertising, but advertising is already stopped!\n");
stiaje 10:67e4694f2d74 173 }
stiaje 10:67e4694f2d74 174 }
stiaje 10:67e4694f2d74 175
stiaje 10:67e4694f2d74 176
stiaje 10:67e4694f2d74 177 void Puck::addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties) {
stiaje 10:67e4694f2d74 178 MBED_ASSERT(bytes <= 20);
stiaje 10:67e4694f2d74 179
stiaje 10:67e4694f2d74 180 uint16_t size = sizeof(uint8_t) * bytes;
stiaje 10:67e4694f2d74 181 uint8_t* value = (uint8_t*) malloc(size);
stiaje 10:67e4694f2d74 182 GattCharacteristic* characteristic = new GattCharacteristic(characteristicUuid, value, size, size, properties);
stiaje 10:67e4694f2d74 183 characteristics.push_back(characteristic);
stiaje 10:67e4694f2d74 184 GattService* service = NULL;
stiaje 10:67e4694f2d74 185 int removeIndex = -1;
stiaje 10:67e4694f2d74 186 for(int i = 0; i < services.size(); i++) {
stiaje 10:67e4694f2d74 187 if(isEqualUUID(&services[i]->getUUID(), serviceUuid)) {
stiaje 10:67e4694f2d74 188 service = services[i];
stiaje 10:67e4694f2d74 189 removeIndex = i;
stiaje 10:67e4694f2d74 190 break;
stiaje 10:67e4694f2d74 191 }
stiaje 10:67e4694f2d74 192 }
stiaje 10:67e4694f2d74 193 GattCharacteristic** characteristics = NULL;
stiaje 10:67e4694f2d74 194 int characteristicsLength = 0;
stiaje 10:67e4694f2d74 195 if(service != NULL) {
stiaje 10:67e4694f2d74 196 characteristicsLength = service->getCharacteristicCount() + 1;
stiaje 10:67e4694f2d74 197 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
stiaje 10:67e4694f2d74 198 for(int i = 0; i < characteristicsLength; i++) {
stiaje 10:67e4694f2d74 199 characteristics[i] = service->getCharacteristic(i);
stiaje 10:67e4694f2d74 200 }
stiaje 10:67e4694f2d74 201 services.erase(services.begin() + removeIndex);
stiaje 10:67e4694f2d74 202 delete service;
stiaje 10:67e4694f2d74 203 free(previousCharacteristics);
stiaje 10:67e4694f2d74 204 } else {
stiaje 10:67e4694f2d74 205 characteristicsLength = 1;
stiaje 10:67e4694f2d74 206 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
stiaje 10:67e4694f2d74 207 }
stiaje 10:67e4694f2d74 208 characteristics[characteristicsLength - 1] = characteristic;
stiaje 10:67e4694f2d74 209 previousCharacteristics = characteristics;
stiaje 10:67e4694f2d74 210 service = new GattService(serviceUuid, characteristics, characteristicsLength);
stiaje 10:67e4694f2d74 211 services.push_back(service);
stiaje 10:67e4694f2d74 212 }
stiaje 10:67e4694f2d74 213
stiaje 10:67e4694f2d74 214
stiaje 10:67e4694f2d74 215 void Puck::updateCharacteristicValue(const UUID uuid, uint8_t* value, int length) {
stiaje 10:67e4694f2d74 216 GattCharacteristic* characteristic = NULL;
stiaje 10:67e4694f2d74 217 for( int i = 0; i < characteristics.size(); i++) {
stiaje 10:67e4694f2d74 218 if(isEqualUUID(&characteristics[i]->getUUID(), uuid)) {
stiaje 10:67e4694f2d74 219 characteristic = characteristics[i];
stiaje 10:67e4694f2d74 220 break;
stiaje 10:67e4694f2d74 221 }
stiaje 10:67e4694f2d74 222 }
stiaje 10:67e4694f2d74 223 if(characteristic != NULL) {
stiaje 10:67e4694f2d74 224 ble.updateCharacteristicValue(characteristic->getHandle(), value, length);
stiaje 10:67e4694f2d74 225 LOG_VERBOSE("Updated characteristic value.\n");
stiaje 10:67e4694f2d74 226 } else {
stiaje 10:67e4694f2d74 227 LOG_WARN("Tried to update an unkown characteristic!\n");
stiaje 10:67e4694f2d74 228 }
stiaje 10:67e4694f2d74 229 }
stiaje 10:67e4694f2d74 230
stiaje 10:67e4694f2d74 231 bool Puck::drive() {
stiaje 10:67e4694f2d74 232 ble.waitForEvent();
stiaje 10:67e4694f2d74 233 if(state == DISCONNECTED) {
stiaje 10:67e4694f2d74 234 startAdvertising();
stiaje 10:67e4694f2d74 235 }
stiaje 10:67e4694f2d74 236 while(pendingCallbackStack.size() > 0) {
stiaje 10:67e4694f2d74 237 LOG_VERBOSE("PendingCallbackStack size: %i\n", pendingCallbackStack.size());
stiaje 10:67e4694f2d74 238 pendingCallbackStack.back()(pendingCallbackParameterStack.back());
stiaje 10:67e4694f2d74 239 pendingCallbackStack.pop_back();
stiaje 10:67e4694f2d74 240 pendingCallbackParameterStack.pop_back();
stiaje 10:67e4694f2d74 241 LOG_VERBOSE("Callback fired\n");
stiaje 10:67e4694f2d74 242 }
stiaje 10:67e4694f2d74 243 return true;
stiaje 10:67e4694f2d74 244 }
stiaje 10:67e4694f2d74 245
stiaje 10:67e4694f2d74 246
stiaje 10:67e4694f2d74 247 void Puck::onCharacteristicWrite(const UUID uuid, CharacteristicWriteCallback callback) {
stiaje 10:67e4694f2d74 248 CharacteristicWriteCallbacks* cb = NULL;
stiaje 10:67e4694f2d74 249 for(int i = 0; i< writeCallbacks.size(); i++) {
stiaje 10:67e4694f2d74 250 if(isEqualUUID(writeCallbacks[i]->uuid, uuid)) {
stiaje 10:67e4694f2d74 251 cb = writeCallbacks[i];
stiaje 10:67e4694f2d74 252 break;
stiaje 10:67e4694f2d74 253 }
stiaje 10:67e4694f2d74 254 }
stiaje 10:67e4694f2d74 255 if(cb == NULL) {
stiaje 10:67e4694f2d74 256 cb = (CharacteristicWriteCallbacks*) malloc(sizeof(CharacteristicWriteCallbacks));
stiaje 10:67e4694f2d74 257 cb->uuid = &uuid;
stiaje 10:67e4694f2d74 258 cb->callbacks = new std::vector<CharacteristicWriteCallback>();
stiaje 10:67e4694f2d74 259 writeCallbacks.push_back(cb);
stiaje 10:67e4694f2d74 260 }
stiaje 10:67e4694f2d74 261 cb->callbacks->push_back(callback);
stiaje 10:67e4694f2d74 262 LOG_VERBOSE("Bound characteristic write callback (uuid: %x, callback: %x)\n", uuid, callback);
stiaje 10:67e4694f2d74 263 }
stiaje 10:67e4694f2d74 264
stiaje 10:67e4694f2d74 265
stiaje 10:67e4694f2d74 266 uint8_t* Puck::getCharacteristicValue(const UUID uuid) {
stiaje 10:67e4694f2d74 267 LOG_VERBOSE("Reading characteristic value for UUID %x\n", uuid);
stiaje 10:67e4694f2d74 268 for(int i = 0; i < characteristics.size(); i++) {
stiaje 10:67e4694f2d74 269 GattCharacteristic* characteristic = characteristics[i];
stiaje 10:67e4694f2d74 270 if(isEqualUUID(&characteristic->getUUID(), uuid)) {
stiaje 10:67e4694f2d74 271 return characteristic->getValuePtr();
stiaje 10:67e4694f2d74 272 }
stiaje 10:67e4694f2d74 273 }
stiaje 10:67e4694f2d74 274 LOG_WARN("Tried to read an unknown characteristic!");
stiaje 10:67e4694f2d74 275 return NULL;
stiaje 10:67e4694f2d74 276 }
stiaje 10:67e4694f2d74 277
stiaje 10:67e4694f2d74 278
stiaje 10:67e4694f2d74 279 void Puck::onDataWritten(uint16_t handle) {
stiaje 10:67e4694f2d74 280 for (int i = 0; i < characteristics.size(); i++) {
stiaje 10:67e4694f2d74 281 GattCharacteristic* characteristic = characteristics[i];
stiaje 10:67e4694f2d74 282 if (characteristic->getHandle() == handle) {
stiaje 10:67e4694f2d74 283 uint16_t maxLength = characteristic->getMaxLength();
stiaje 10:67e4694f2d74 284 ble.readCharacteristicValue(handle, characteristic->getValuePtr(), &maxLength);
stiaje 10:67e4694f2d74 285 for(int j = 0; j < writeCallbacks.size(); j++) {
stiaje 10:67e4694f2d74 286 CharacteristicWriteCallbacks* characteristicWriteCallbacks = writeCallbacks[j];
stiaje 10:67e4694f2d74 287 if(isEqualUUID(characteristicWriteCallbacks->uuid, characteristic->getUUID())) {
stiaje 10:67e4694f2d74 288 for(int k = 0; k < characteristicWriteCallbacks->callbacks->size(); k++) {
stiaje 10:67e4694f2d74 289 pendingCallbackStack.push_back(characteristicWriteCallbacks->callbacks->at(k));
stiaje 10:67e4694f2d74 290 pendingCallbackParameterStack.push_back(characteristic->getValuePtr());
stiaje 10:67e4694f2d74 291 }
stiaje 10:67e4694f2d74 292 }
stiaje 10:67e4694f2d74 293 return;
stiaje 10:67e4694f2d74 294 }
stiaje 10:67e4694f2d74 295 }
stiaje 10:67e4694f2d74 296 }
stiaje 10:67e4694f2d74 297 }
stiaje 10:67e4694f2d74 298
stiaje 10:67e4694f2d74 299
stiaje 10:67e4694f2d74 300
stiaje 10:67e4694f2d74 301 #endif // __PUCK_HPP__