A library for easier setup and prototyping of IoT devices (pucks), by collecting everything that is common for all pucks in one place.

Dependencies:   BLE_API nRF51822

Dependents:   ir-puck display-puck ir-puck2 BLE_ScoringDevice ... more

/media/uploads/stiaje/header.jpg

Introduction

Raspberry Pi took the maker community by storm when it launched in 2012. With its internet access it allowed small projects to be internet-of-things enabled. We have created a platform to take this one step further.

Our platform, called the Puck platform, is an internet of things platform for mbed. mbed makes it easy to program embedded hardware for people new to embedded systems. Our platform is built upon the first mbed chip with Bluetooth, the nRF51822 created by Nordic Semiconductor. We hope to create a community around these BLE devices where people contribute to the project, and share their designs with each other. Everything is open-source, of course, with lots of supporting materials.

We make it easy to rapidly prototype and develop Bluetooth LE enabled devices - get up and running in under 10 lines of code.

Tutorials and in-depth documentation is available at the project's GitHub page

Pucks

We've developed a handful of awesome examples to demonstrate the platform. These examples are named 'Pucks'. By talking to the internet through your smartphone, the barrier to creating your own Internet of Things device is lower than ever.

Committer:
aleksanb
Date:
Fri Aug 01 13:31:46 2014 +0000
Revision:
16:fb8678ee25b0
Parent:
10:67e4694f2d74
Child:
17:23a05bd2fe2b
Document puck library.

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