Press buttons to activate the LED.

Dependencies:   BLE_API nRF51822

Fork of Puck by Nordic Pucks

Committer:
aleksanb
Date:
Fri Aug 01 14:15:25 2014 +0000
Revision:
17:23a05bd2fe2b
Parent:
16:fb8678ee25b0
Child:
18:4c95a470d778
More documentation.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
sigveseb 3:5432b38585ea 1 #ifndef __PUCK_HPP__
sigveseb 3:5432b38585ea 2 #define __PUCK_HPP__
sigveseb 3:5432b38585ea 3
sigveseb 3:5432b38585ea 4 #include "BLEDevice.h"
sigveseb 3:5432b38585ea 5 #include <vector>
cristea 7:c07c01c2a741 6 #include "Log.h"
sigveseb 3:5432b38585ea 7
sigveseb 9:ba0527c6b6d0 8 enum PuckState {
sigveseb 3:5432b38585ea 9 CONNECTING,
sigveseb 3:5432b38585ea 10 CONNECTED,
sigveseb 3:5432b38585ea 11 ADVERTISING,
sigveseb 3:5432b38585ea 12 DISCONNECTED
sigveseb 3:5432b38585ea 13 };
sigveseb 3:5432b38585ea 14
sigveseb 3:5432b38585ea 15 const UUID stringToUUID(const char* str);
sigveseb 3:5432b38585ea 16
sigveseb 3:5432b38585ea 17 typedef void (*CharacteristicWriteCallback)(uint8_t* value);
sigveseb 3:5432b38585ea 18
sigveseb 3:5432b38585ea 19 typedef struct {
sigveseb 3:5432b38585ea 20 const UUID* uuid;
sigveseb 3:5432b38585ea 21 std::vector<CharacteristicWriteCallback>* callbacks;
sigveseb 3:5432b38585ea 22 } CharacteristicWriteCallbacks;
sigveseb 3:5432b38585ea 23
aleksanb 17:23a05bd2fe2b 24 /**
aleksanb 17:23a05bd2fe2b 25 * @brief A library for easier setup and prototyping of IoT devices (pucks), by collecting everything that is common for all pucks in one place.
aleksanb 16:fb8678ee25b0 26 *
aleksanb 16:fb8678ee25b0 27 */
sigveseb 3:5432b38585ea 28 class Puck {
sigveseb 3:5432b38585ea 29 private:
sigveseb 3:5432b38585ea 30 Puck() {}
sigveseb 3:5432b38585ea 31 Puck(const Puck&);
sigveseb 3:5432b38585ea 32 Puck& operator=(const Puck&);
sigveseb 3:5432b38585ea 33
sigveseb 3:5432b38585ea 34 BLEDevice ble;
sigveseb 3:5432b38585ea 35 uint8_t beaconPayload[25];
sigveseb 3:5432b38585ea 36 PuckState state;
sigveseb 3:5432b38585ea 37 std::vector<GattService*> services;
sigveseb 3:5432b38585ea 38 std::vector<GattCharacteristic*> characteristics;
sigveseb 3:5432b38585ea 39 std::vector<CharacteristicWriteCallbacks*> writeCallbacks;
sigveseb 3:5432b38585ea 40 std::vector<CharacteristicWriteCallback> pendingCallbackStack;
sigveseb 3:5432b38585ea 41 std::vector<uint8_t*> pendingCallbackParameterStack;
sigveseb 3:5432b38585ea 42
stiaje 4:91506772210d 43 GattCharacteristic **previousCharacteristics;
stiaje 4:91506772210d 44
sigveseb 3:5432b38585ea 45 public:
sigveseb 3:5432b38585ea 46 static Puck &getPuck();
sigveseb 3:5432b38585ea 47
stiaje 5:2f2a2ac6b231 48 BLEDevice &getBle() { return ble; }
sigveseb 3:5432b38585ea 49 PuckState getState() { return state; }
sigveseb 3:5432b38585ea 50 void setState(PuckState state);
sigveseb 3:5432b38585ea 51 void init(uint16_t minor);
sigveseb 3:5432b38585ea 52 void startAdvertising();
sigveseb 3:5432b38585ea 53 void stopAdvertising();
sigveseb 9:ba0527c6b6d0 54 void disconnect();
sigveseb 3:5432b38585ea 55 bool drive();
sigveseb 9:ba0527c6b6d0 56 int countFreeMemory();
sigveseb 3:5432b38585ea 57 void onDataWritten(uint16_t handle);
sigveseb 3:5432b38585ea 58 void addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties = 0xA);
stiaje 10:67e4694f2d74 59
sigveseb 9:ba0527c6b6d0 60 void onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback);
sigveseb 8:49ffd38fb401 61 void updateCharacteristicValue(const UUID uuid, uint8_t* value, int length);
stiaje 10:67e4694f2d74 62
sigveseb 3:5432b38585ea 63 uint8_t* getCharacteristicValue(const UUID uuid);
sigveseb 3:5432b38585ea 64 };
sigveseb 3:5432b38585ea 65
aleksanb 16:fb8678ee25b0 66 /**
aleksanb 16:fb8678ee25b0 67 * @brief Returns singleton instance of puck object.
aleksanb 16:fb8678ee25b0 68 *
aleksanb 16:fb8678ee25b0 69 * @return singleton instance of puck object.
aleksanb 16:fb8678ee25b0 70 */
sigveseb 3:5432b38585ea 71 Puck &Puck::getPuck() {
sigveseb 3:5432b38585ea 72 static Puck _puckSingletonInstance;
sigveseb 3:5432b38585ea 73 return _puckSingletonInstance;
sigveseb 3:5432b38585ea 74 }
sigveseb 3:5432b38585ea 75
sigveseb 3:5432b38585ea 76
sigveseb 3:5432b38585ea 77 void onDisconnection(void) {
sigveseb 3:5432b38585ea 78 LOG_INFO("Disconnected.\n");
sigveseb 3:5432b38585ea 79 Puck::getPuck().setState(DISCONNECTED);
sigveseb 3:5432b38585ea 80 }
sigveseb 3:5432b38585ea 81
sigveseb 3:5432b38585ea 82 void onConnection(void) {
sigveseb 3:5432b38585ea 83 LOG_INFO("Connected.\n");
sigveseb 3:5432b38585ea 84 Puck::getPuck().setState(CONNECTED);
sigveseb 3:5432b38585ea 85 }
sigveseb 3:5432b38585ea 86
sigveseb 3:5432b38585ea 87 void onDataWrittenCallback(uint16_t handle) {
sigveseb 3:5432b38585ea 88 Puck::getPuck().onDataWritten(handle);
sigveseb 3:5432b38585ea 89 }
sigveseb 3:5432b38585ea 90
sigveseb 3:5432b38585ea 91 bool isEqualUUID(const UUID* uuidA, const UUID uuidB) {
sigveseb 3:5432b38585ea 92 const uint8_t* uuidABase = uuidA->getBaseUUID();
sigveseb 3:5432b38585ea 93 const uint8_t* uuidBBase = uuidB.getBaseUUID();
sigveseb 9:ba0527c6b6d0 94
sigveseb 3:5432b38585ea 95 for(int i = 0; i < 16; i++) {
sigveseb 3:5432b38585ea 96 if(uuidABase[i] != uuidBBase[i]) {
sigveseb 3:5432b38585ea 97 return false;
sigveseb 3:5432b38585ea 98 }
sigveseb 3:5432b38585ea 99 }
sigveseb 9:ba0527c6b6d0 100 if(uuidA->getShortUUID() != uuidB.getShortUUID()) {
sigveseb 9:ba0527c6b6d0 101 return false;
sigveseb 9:ba0527c6b6d0 102 }
sigveseb 3:5432b38585ea 103 return true;
sigveseb 3:5432b38585ea 104 }
sigveseb 3:5432b38585ea 105
aleksanb 16:fb8678ee25b0 106 /**
aleksanb 16:fb8678ee25b0 107 * @brief Returns UUID representation of a 16-character string.
aleksanb 16:fb8678ee25b0 108 *
aleksanb 16:fb8678ee25b0 109 */
sigveseb 3:5432b38585ea 110 const UUID stringToUUID(const char* str) {
sigveseb 3:5432b38585ea 111 uint8_t array[16];
sigveseb 3:5432b38585ea 112 for(int i = 0; i < 16; i++) {
sigveseb 3:5432b38585ea 113 array[i] = str[i];
sigveseb 3:5432b38585ea 114 }
sigveseb 3:5432b38585ea 115 return UUID(array);
sigveseb 3:5432b38585ea 116 }
sigveseb 3:5432b38585ea 117
sigveseb 9:ba0527c6b6d0 118 void Puck::disconnect() {
sigveseb 9:ba0527c6b6d0 119 ble.disconnect();
sigveseb 9:ba0527c6b6d0 120 }
sigveseb 9:ba0527c6b6d0 121
aleksanb 16:fb8678ee25b0 122 /**
aleksanb 16:fb8678ee25b0 123 * @brief Approximates malloc-able heap space. Do not use in production code, as it may crash.
aleksanb 16:fb8678ee25b0 124 *
aleksanb 16:fb8678ee25b0 125 */
sigveseb 9:ba0527c6b6d0 126 int Puck::countFreeMemory() {
sigveseb 9:ba0527c6b6d0 127 int blocksize = 256;
sigveseb 9:ba0527c6b6d0 128 int amount = 0;
sigveseb 9:ba0527c6b6d0 129 while (blocksize > 0) {
sigveseb 9:ba0527c6b6d0 130 amount += blocksize;
sigveseb 9:ba0527c6b6d0 131 LOG_VERBOSE("Trying to malloc %i bytes... ", amount);
sigveseb 9:ba0527c6b6d0 132 char *p = (char *) malloc(amount);
sigveseb 9:ba0527c6b6d0 133 if (p == NULL) {
sigveseb 9:ba0527c6b6d0 134 LOG_VERBOSE("FAIL!\n", amount);
sigveseb 9:ba0527c6b6d0 135 amount -= blocksize;
sigveseb 9:ba0527c6b6d0 136 blocksize /= 2;
sigveseb 9:ba0527c6b6d0 137 } else {
sigveseb 9:ba0527c6b6d0 138 free(p);
sigveseb 9:ba0527c6b6d0 139 LOG_VERBOSE("OK!\n", amount);
sigveseb 9:ba0527c6b6d0 140 }
sigveseb 9:ba0527c6b6d0 141 }
sigveseb 9:ba0527c6b6d0 142 LOG_DEBUG("Free memory: %i bytes.\n", amount);
sigveseb 9:ba0527c6b6d0 143 return amount;
sigveseb 9:ba0527c6b6d0 144 }
sigveseb 9:ba0527c6b6d0 145
sigveseb 3:5432b38585ea 146 void Puck::setState(PuckState state) {
sigveseb 3:5432b38585ea 147 LOG_DEBUG("Changed state to %i\n", state);
sigveseb 3:5432b38585ea 148 this->state = state;
sigveseb 3:5432b38585ea 149 }
sigveseb 3:5432b38585ea 150
aleksanb 16:fb8678ee25b0 151 /**
aleksanb 16:fb8678ee25b0 152 * @brief Call after finishing configuring puck (adding services, characteristics, callbacks).
aleksanb 16:fb8678ee25b0 153 Starts advertising over bluetooth le.
aleksanb 16:fb8678ee25b0 154 *
aleksanb 16:fb8678ee25b0 155 * @parameter minor
aleksanb 16:fb8678ee25b0 156 * Minor number to use for iBeacon identifier.
aleksanb 16:fb8678ee25b0 157 *
aleksanb 16:fb8678ee25b0 158 */
sigveseb 3:5432b38585ea 159 void Puck::init(uint16_t minor) {
sigveseb 3:5432b38585ea 160 /*
sigveseb 3:5432b38585ea 161 * The Beacon payload (encapsulated within the MSD advertising data structure)
sigveseb 3:5432b38585ea 162 * has the following composition:
sigveseb 3:5432b38585ea 163 * 128-Bit UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
sigveseb 3:5432b38585ea 164 * Major/Minor = 1337 / XXXX
sigveseb 3:5432b38585ea 165 * Tx Power = C8
sigveseb 3:5432b38585ea 166 */
sigveseb 3:5432b38585ea 167 uint8_t beaconPayloadTemplate[] = {
sigveseb 3:5432b38585ea 168 0x00, 0x00, // Company identifier code (0x004C == Apple)
sigveseb 3:5432b38585ea 169 0x02, // ID
sigveseb 3:5432b38585ea 170 0x15, // length of the remaining payload
sigveseb 3:5432b38585ea 171 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID
sigveseb 3:5432b38585ea 172 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61,
sigveseb 3:5432b38585ea 173 0x13, 0x37, // the major value to differenciate a location (Our app requires 1337 as major number)
sigveseb 3:5432b38585ea 174 0x00, 0x00, // the minor value to differenciate a location (Change this to differentiate location pucks)
sigveseb 3:5432b38585ea 175 0xC8 // 2's complement of the Tx power (-56dB)
sigveseb 3:5432b38585ea 176 };
sigveseb 3:5432b38585ea 177 beaconPayloadTemplate[22] = minor >> 8;
sigveseb 3:5432b38585ea 178 beaconPayloadTemplate[23] = minor & 255;
sigveseb 3:5432b38585ea 179
sigveseb 3:5432b38585ea 180 for (int i=0; i < 25; i++) {
sigveseb 3:5432b38585ea 181 beaconPayload[i] = beaconPayloadTemplate[i];
sigveseb 3:5432b38585ea 182 }
sigveseb 3:5432b38585ea 183
sigveseb 3:5432b38585ea 184 ble.init();
sigveseb 9:ba0527c6b6d0 185 LOG_DEBUG("Inited BLEDevice.\n");
sigveseb 3:5432b38585ea 186 setState(DISCONNECTED);
sigveseb 3:5432b38585ea 187
sigveseb 3:5432b38585ea 188 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
sigveseb 9:ba0527c6b6d0 189 LOG_DEBUG("Accumulate advertising payload: BREDR_NOT_SUPPORTED.\n");
sigveseb 3:5432b38585ea 190
sigveseb 3:5432b38585ea 191 ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, beaconPayload, sizeof(beaconPayload));
sigveseb 9:ba0527c6b6d0 192 LOG_DEBUG("Accumulate advertising payload: beacon data.\n");
sigveseb 3:5432b38585ea 193
sigveseb 3:5432b38585ea 194 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
sigveseb 9:ba0527c6b6d0 195 LOG_DEBUG("Setting advertising type: ADV_CONNECTABLE_UNDIRECTED.\n");
sigveseb 3:5432b38585ea 196
sigveseb 3:5432b38585ea 197 int hundredMillisecondsInAdvertisingIntervalFormat = 160;
sigveseb 3:5432b38585ea 198 ble.setAdvertisingInterval(hundredMillisecondsInAdvertisingIntervalFormat);
sigveseb 9:ba0527c6b6d0 199 LOG_DEBUG("Set advertising interval: 160 (100 ms).\n");
sigveseb 3:5432b38585ea 200
sigveseb 3:5432b38585ea 201 ble.onDisconnection(onDisconnection);
sigveseb 3:5432b38585ea 202 ble.onConnection(onConnection);
sigveseb 3:5432b38585ea 203 ble.onDataWritten(onDataWrittenCallback);
sigveseb 9:ba0527c6b6d0 204 LOG_DEBUG("Hooked up internal event handlers.\n");
sigveseb 3:5432b38585ea 205
sigveseb 3:5432b38585ea 206 for(int i = 0; i < services.size(); i++) {
sigveseb 3:5432b38585ea 207 ble.addService(*services[i]);
sigveseb 9:ba0527c6b6d0 208 LOG_DEBUG("Added service %x to BLEDevice\n", services[i]);
sigveseb 3:5432b38585ea 209 }
sigveseb 3:5432b38585ea 210
sigveseb 3:5432b38585ea 211 LOG_INFO("Inited puck as 0x%X.\n", minor);
sigveseb 3:5432b38585ea 212 }
sigveseb 3:5432b38585ea 213
sigveseb 3:5432b38585ea 214 void Puck::startAdvertising() {
sigveseb 3:5432b38585ea 215 ble.startAdvertising();
sigveseb 3:5432b38585ea 216 LOG_INFO("Starting to advertise.\n");
sigveseb 3:5432b38585ea 217 setState(ADVERTISING);
sigveseb 3:5432b38585ea 218 }
sigveseb 3:5432b38585ea 219
sigveseb 3:5432b38585ea 220 void Puck::stopAdvertising() {
sigveseb 3:5432b38585ea 221 if(state == ADVERTISING) {
sigveseb 3:5432b38585ea 222 ble.stopAdvertising();
sigveseb 3:5432b38585ea 223 LOG_INFO("Stopped advertising.\n");
sigveseb 3:5432b38585ea 224 setState(DISCONNECTED);
sigveseb 3:5432b38585ea 225 } else {
sigveseb 3:5432b38585ea 226 LOG_WARN("Tried to stop advertising, but advertising is already stopped!\n");
sigveseb 3:5432b38585ea 227 }
sigveseb 3:5432b38585ea 228 }
sigveseb 3:5432b38585ea 229
aleksanb 16:fb8678ee25b0 230 /**
aleksanb 16:fb8678ee25b0 231 * @brief Extends the given gatt service with the given gatt characteristic.
aleksanb 16:fb8678ee25b0 232 * If the service doesn't exist, it is created.
aleksanb 16:fb8678ee25b0 233 *
aleksanb 16:fb8678ee25b0 234 * @param serviceUuid
aleksanb 16:fb8678ee25b0 235 UUID of the gatt service to be extended.
aleksanb 16:fb8678ee25b0 236 *
aleksanb 16:fb8678ee25b0 237 * @param characteristicUuid
aleksanb 16:fb8678ee25b0 238 * UUID to use for this characteristic.
aleksanb 16:fb8678ee25b0 239 *
aleksanb 16:fb8678ee25b0 240 * @param bytes
aleksanb 16:fb8678ee25b0 241 * Length in bytes of this characteristic's value.
aleksanb 16:fb8678ee25b0 242 *
aleksanb 16:fb8678ee25b0 243 * @param properties
aleksanb 16:fb8678ee25b0 244 * 8-bit bit field containing the characteristic's properties. See @ref ble_gatt_char_properties_t.
aleksanb 16:fb8678ee25b0 245 *
aleksanb 16:fb8678ee25b0 246 * @return Void.
aleksanb 16:fb8678ee25b0 247 */
sigveseb 3:5432b38585ea 248 void Puck::addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties) {
sigveseb 3:5432b38585ea 249 MBED_ASSERT(bytes <= 20);
sigveseb 3:5432b38585ea 250 uint16_t size = sizeof(uint8_t) * bytes;
sigveseb 3:5432b38585ea 251 uint8_t* value = (uint8_t*) malloc(size);
sigveseb 9:ba0527c6b6d0 252 if(value == NULL) {
sigveseb 9:ba0527c6b6d0 253 LOG_ERROR("Unable to malloc value for characteristic. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 254 }
sigveseb 9:ba0527c6b6d0 255
sigveseb 3:5432b38585ea 256 GattCharacteristic* characteristic = new GattCharacteristic(characteristicUuid, value, size, size, properties);
sigveseb 3:5432b38585ea 257 characteristics.push_back(characteristic);
sigveseb 9:ba0527c6b6d0 258
sigveseb 9:ba0527c6b6d0 259
sigveseb 3:5432b38585ea 260 GattService* service = NULL;
sigveseb 9:ba0527c6b6d0 261
sigveseb 3:5432b38585ea 262 int removeIndex = -1;
sigveseb 3:5432b38585ea 263 for(int i = 0; i < services.size(); i++) {
sigveseb 3:5432b38585ea 264 if(isEqualUUID(&services[i]->getUUID(), serviceUuid)) {
sigveseb 3:5432b38585ea 265 service = services[i];
sigveseb 3:5432b38585ea 266 removeIndex = i;
sigveseb 3:5432b38585ea 267 break;
sigveseb 3:5432b38585ea 268 }
sigveseb 3:5432b38585ea 269 }
sigveseb 3:5432b38585ea 270 GattCharacteristic** characteristics = NULL;
sigveseb 3:5432b38585ea 271 int characteristicsLength = 0;
sigveseb 3:5432b38585ea 272 if(service != NULL) {
sigveseb 3:5432b38585ea 273 characteristicsLength = service->getCharacteristicCount() + 1;
sigveseb 3:5432b38585ea 274 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
sigveseb 9:ba0527c6b6d0 275 if(characteristics == NULL) {
sigveseb 9:ba0527c6b6d0 276 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 277 }
sigveseb 3:5432b38585ea 278 for(int i = 0; i < characteristicsLength; i++) {
sigveseb 3:5432b38585ea 279 characteristics[i] = service->getCharacteristic(i);
sigveseb 3:5432b38585ea 280 }
sigveseb 3:5432b38585ea 281 services.erase(services.begin() + removeIndex);
sigveseb 3:5432b38585ea 282 delete service;
stiaje 4:91506772210d 283 free(previousCharacteristics);
sigveseb 3:5432b38585ea 284 } else {
sigveseb 3:5432b38585ea 285 characteristicsLength = 1;
sigveseb 3:5432b38585ea 286 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
sigveseb 9:ba0527c6b6d0 287 if(characteristics == NULL) {
sigveseb 9:ba0527c6b6d0 288 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 289 }
sigveseb 3:5432b38585ea 290 }
sigveseb 9:ba0527c6b6d0 291
sigveseb 3:5432b38585ea 292 characteristics[characteristicsLength - 1] = characteristic;
stiaje 4:91506772210d 293 previousCharacteristics = characteristics;
sigveseb 3:5432b38585ea 294 service = new GattService(serviceUuid, characteristics, characteristicsLength);
sigveseb 3:5432b38585ea 295 services.push_back(service);
sigveseb 9:ba0527c6b6d0 296 LOG_DEBUG("Added characteristic.\n");
sigveseb 3:5432b38585ea 297 }
sigveseb 3:5432b38585ea 298
aleksanb 16:fb8678ee25b0 299 /**
aleksanb 16:fb8678ee25b0 300 * @brief Update the value of the given gatt characteristic.
aleksanb 16:fb8678ee25b0 301 *
aleksanb 16:fb8678ee25b0 302 * @param uuid
aleksanb 16:fb8678ee25b0 303 UUID of the gatt characteristic to be updated.
aleksanb 16:fb8678ee25b0 304 *
aleksanb 16:fb8678ee25b0 305 * @param value
aleksanb 16:fb8678ee25b0 306 * New value of the characteristic.
aleksanb 16:fb8678ee25b0 307 *
aleksanb 16:fb8678ee25b0 308 * @param length
aleksanb 16:fb8678ee25b0 309 * Length in bytes of the characteristic's value.
aleksanb 16:fb8678ee25b0 310 *
aleksanb 16:fb8678ee25b0 311 * @return Void.
aleksanb 16:fb8678ee25b0 312 */
sigveseb 8:49ffd38fb401 313 void Puck::updateCharacteristicValue(const UUID uuid, uint8_t* value, int length) {
sigveseb 8:49ffd38fb401 314 GattCharacteristic* characteristic = NULL;
sigveseb 8:49ffd38fb401 315 for( int i = 0; i < characteristics.size(); i++) {
sigveseb 8:49ffd38fb401 316 if(isEqualUUID(&characteristics[i]->getUUID(), uuid)) {
sigveseb 8:49ffd38fb401 317 characteristic = characteristics[i];
sigveseb 8:49ffd38fb401 318 break;
sigveseb 8:49ffd38fb401 319 }
sigveseb 8:49ffd38fb401 320 }
sigveseb 8:49ffd38fb401 321 if(characteristic != NULL) {
sigveseb 8:49ffd38fb401 322 ble.updateCharacteristicValue(characteristic->getHandle(), value, length);
sigveseb 8:49ffd38fb401 323 LOG_VERBOSE("Updated characteristic value.\n");
sigveseb 8:49ffd38fb401 324 } else {
sigveseb 8:49ffd38fb401 325 LOG_WARN("Tried to update an unkown characteristic!\n");
sigveseb 8:49ffd38fb401 326 }
sigveseb 8:49ffd38fb401 327 }
sigveseb 8:49ffd38fb401 328
aleksanb 16:fb8678ee25b0 329 /**
aleksanb 16:fb8678ee25b0 330 * @brief Pass control to the bluetooth stack, executing pending callbacks afterwards. Should be used inside a while condition loop.
aleksanb 16:fb8678ee25b0 331 *
aleksanb 16:fb8678ee25b0 332 * Example:
aleksanb 16:fb8678ee25b0 333 * @code
aleksanb 17:23a05bd2fe2b 334 * while (puck->drive()) {
aleksanb 16:fb8678ee25b0 335 * // Do stuff
aleksanb 16:fb8678ee25b0 336 * }
aleksanb 16:fb8678ee25b0 337 * @endcode
aleksanb 16:fb8678ee25b0 338 *
aleksanb 16:fb8678ee25b0 339 * @return true.
aleksanb 16:fb8678ee25b0 340 *
aleksanb 16:fb8678ee25b0 341 */
sigveseb 3:5432b38585ea 342 bool Puck::drive() {
sigveseb 3:5432b38585ea 343 ble.waitForEvent();
sigveseb 3:5432b38585ea 344 if(state == DISCONNECTED) {
sigveseb 3:5432b38585ea 345 startAdvertising();
sigveseb 3:5432b38585ea 346 }
sigveseb 3:5432b38585ea 347 while(pendingCallbackStack.size() > 0) {
sigveseb 3:5432b38585ea 348 pendingCallbackStack.back()(pendingCallbackParameterStack.back());
sigveseb 3:5432b38585ea 349 pendingCallbackStack.pop_back();
sigveseb 3:5432b38585ea 350 pendingCallbackParameterStack.pop_back();
sigveseb 3:5432b38585ea 351 }
sigveseb 3:5432b38585ea 352 return true;
sigveseb 3:5432b38585ea 353 }
sigveseb 3:5432b38585ea 354
aleksanb 16:fb8678ee25b0 355 /**
aleksanb 16:fb8678ee25b0 356 * @brief Register callback to be triggered on characteristic write.
aleksanb 16:fb8678ee25b0 357 *
aleksanb 16:fb8678ee25b0 358 * @parameter uuid
aleksanb 16:fb8678ee25b0 359 * UUID of the gatt characteristic to bind callback to.
aleksanb 16:fb8678ee25b0 360 *
aleksanb 16:fb8678ee25b0 361 * @parameter callback
aleksanb 16:fb8678ee25b0 362 * CharacteristicWriteCallback to be executed on characteristic write.
aleksanb 16:fb8678ee25b0 363 *
aleksanb 16:fb8678ee25b0 364 * @return Void.
aleksanb 16:fb8678ee25b0 365 *
aleksanb 16:fb8678ee25b0 366 */
sigveseb 9:ba0527c6b6d0 367 void Puck::onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback) {
sigveseb 3:5432b38585ea 368 CharacteristicWriteCallbacks* cb = NULL;
sigveseb 3:5432b38585ea 369 for(int i = 0; i< writeCallbacks.size(); i++) {
sigveseb 9:ba0527c6b6d0 370 if(isEqualUUID(writeCallbacks[i]->uuid, *uuid)) {
sigveseb 3:5432b38585ea 371 cb = writeCallbacks[i];
sigveseb 3:5432b38585ea 372 break;
sigveseb 3:5432b38585ea 373 }
sigveseb 3:5432b38585ea 374 }
sigveseb 3:5432b38585ea 375 if(cb == NULL) {
sigveseb 3:5432b38585ea 376 cb = (CharacteristicWriteCallbacks*) malloc(sizeof(CharacteristicWriteCallbacks));
sigveseb 9:ba0527c6b6d0 377 if(cb == NULL) {
sigveseb 9:ba0527c6b6d0 378 LOG_ERROR("Could not malloc CharacteristicWriteCallbacks container. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 379 }
sigveseb 9:ba0527c6b6d0 380 cb->uuid = uuid;
sigveseb 3:5432b38585ea 381 cb->callbacks = new std::vector<CharacteristicWriteCallback>();
sigveseb 3:5432b38585ea 382 writeCallbacks.push_back(cb);
sigveseb 3:5432b38585ea 383 }
sigveseb 3:5432b38585ea 384 cb->callbacks->push_back(callback);
sigveseb 3:5432b38585ea 385 LOG_VERBOSE("Bound characteristic write callback (uuid: %x, callback: %x)\n", uuid, callback);
sigveseb 3:5432b38585ea 386 }
sigveseb 3:5432b38585ea 387
aleksanb 16:fb8678ee25b0 388 /**
aleksanb 16:fb8678ee25b0 389 * @brief Returns current value of provided gatt characteristic.
aleksanb 16:fb8678ee25b0 390 *
aleksanb 16:fb8678ee25b0 391 */
sigveseb 3:5432b38585ea 392 uint8_t* Puck::getCharacteristicValue(const UUID uuid) {
sigveseb 3:5432b38585ea 393 LOG_VERBOSE("Reading characteristic value for UUID %x\n", uuid);
sigveseb 3:5432b38585ea 394 for(int i = 0; i < characteristics.size(); i++) {
sigveseb 3:5432b38585ea 395 GattCharacteristic* characteristic = characteristics[i];
sigveseb 3:5432b38585ea 396 if(isEqualUUID(&characteristic->getUUID(), uuid)) {
sigveseb 3:5432b38585ea 397 return characteristic->getValuePtr();
sigveseb 3:5432b38585ea 398 }
sigveseb 3:5432b38585ea 399 }
sigveseb 3:5432b38585ea 400 LOG_WARN("Tried to read an unknown characteristic!");
sigveseb 3:5432b38585ea 401 return NULL;
sigveseb 3:5432b38585ea 402 }
sigveseb 3:5432b38585ea 403
aleksanb 16:fb8678ee25b0 404 /**
aleksanb 16:fb8678ee25b0 405 * @brief For internal use only. Exposed to hack around mbed framework limitation.
aleksanb 16:fb8678ee25b0 406 *
aleksanb 16:fb8678ee25b0 407 */
sigveseb 3:5432b38585ea 408 void Puck::onDataWritten(uint16_t handle) {
sigveseb 3:5432b38585ea 409 for (int i = 0; i < characteristics.size(); i++) {
sigveseb 3:5432b38585ea 410 GattCharacteristic* characteristic = characteristics[i];
sigveseb 3:5432b38585ea 411 if (characteristic->getHandle() == handle) {
sigveseb 3:5432b38585ea 412 uint16_t maxLength = characteristic->getMaxLength();
sigveseb 3:5432b38585ea 413 ble.readCharacteristicValue(handle, characteristic->getValuePtr(), &maxLength);
sigveseb 3:5432b38585ea 414 for(int j = 0; j < writeCallbacks.size(); j++) {
sigveseb 3:5432b38585ea 415 CharacteristicWriteCallbacks* characteristicWriteCallbacks = writeCallbacks[j];
sigveseb 3:5432b38585ea 416 if(isEqualUUID(characteristicWriteCallbacks->uuid, characteristic->getUUID())) {
sigveseb 3:5432b38585ea 417 for(int k = 0; k < characteristicWriteCallbacks->callbacks->size(); k++) {
sigveseb 3:5432b38585ea 418 pendingCallbackStack.push_back(characteristicWriteCallbacks->callbacks->at(k));
sigveseb 3:5432b38585ea 419 pendingCallbackParameterStack.push_back(characteristic->getValuePtr());
sigveseb 3:5432b38585ea 420 }
sigveseb 9:ba0527c6b6d0 421 return;
sigveseb 3:5432b38585ea 422 }
sigveseb 3:5432b38585ea 423 }
sigveseb 3:5432b38585ea 424 }
sigveseb 3:5432b38585ea 425 }
sigveseb 3:5432b38585ea 426 }
sigveseb 3:5432b38585ea 427
sigveseb 3:5432b38585ea 428
sigveseb 3:5432b38585ea 429
sigveseb 3:5432b38585ea 430 #endif // __PUCK_HPP__