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 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__