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:
sigveseb
Date:
Tue Mar 03 20:51:34 2015 +0000
Revision:
20:29b0143f3af3
Parent:
18:4c95a470d778
Child:
21:00a3567124e3
Add setting of device name to puck init

Who changed what in which revision?

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