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:
Timmmm
Date:
Fri Jul 24 18:43:36 2015 +0000
Revision:
25:5ac5f1d1a11e
Parent:
23:21b5ecbc84ea
Update for latest nRF51822 repo.

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