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:
stiaje
Date:
Sun Mar 01 18:32:49 2015 +0000
Revision:
18:4c95a470d778
Parent:
17:23a05bd2fe2b
Parent:
15:bfc682889c15
Child:
20:29b0143f3af3
Merge documentation

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 3:5432b38585ea 208
sigveseb 3:5432b38585ea 209 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
sigveseb 9:ba0527c6b6d0 210 LOG_DEBUG("Accumulate advertising payload: BREDR_NOT_SUPPORTED.\n");
sigveseb 3:5432b38585ea 211
sigveseb 3:5432b38585ea 212 ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, beaconPayload, sizeof(beaconPayload));
sigveseb 9:ba0527c6b6d0 213 LOG_DEBUG("Accumulate advertising payload: beacon data.\n");
sigveseb 3:5432b38585ea 214
sigveseb 3:5432b38585ea 215 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
sigveseb 9:ba0527c6b6d0 216 LOG_DEBUG("Setting advertising type: ADV_CONNECTABLE_UNDIRECTED.\n");
sigveseb 3:5432b38585ea 217
sigveseb 3:5432b38585ea 218 int hundredMillisecondsInAdvertisingIntervalFormat = 160;
sigveseb 3:5432b38585ea 219 ble.setAdvertisingInterval(hundredMillisecondsInAdvertisingIntervalFormat);
sigveseb 9:ba0527c6b6d0 220 LOG_DEBUG("Set advertising interval: 160 (100 ms).\n");
sigveseb 3:5432b38585ea 221
sigveseb 3:5432b38585ea 222 ble.onDisconnection(onDisconnection);
sigveseb 3:5432b38585ea 223 ble.onConnection(onConnection);
sigveseb 3:5432b38585ea 224 ble.onDataWritten(onDataWrittenCallback);
sigveseb 9:ba0527c6b6d0 225 LOG_DEBUG("Hooked up internal event handlers.\n");
sigveseb 3:5432b38585ea 226
sigveseb 3:5432b38585ea 227 for(int i = 0; i < services.size(); i++) {
sigveseb 3:5432b38585ea 228 ble.addService(*services[i]);
sigveseb 9:ba0527c6b6d0 229 LOG_DEBUG("Added service %x to BLEDevice\n", services[i]);
sigveseb 3:5432b38585ea 230 }
sigveseb 3:5432b38585ea 231
sigveseb 3:5432b38585ea 232 LOG_INFO("Inited puck as 0x%X.\n", minor);
sigveseb 3:5432b38585ea 233 }
sigveseb 3:5432b38585ea 234
sigveseb 3:5432b38585ea 235 void Puck::startAdvertising() {
sigveseb 3:5432b38585ea 236 ble.startAdvertising();
sigveseb 3:5432b38585ea 237 LOG_INFO("Starting to advertise.\n");
sigveseb 3:5432b38585ea 238 setState(ADVERTISING);
sigveseb 3:5432b38585ea 239 }
sigveseb 3:5432b38585ea 240
sigveseb 3:5432b38585ea 241 void Puck::stopAdvertising() {
sigveseb 3:5432b38585ea 242 if(state == ADVERTISING) {
sigveseb 3:5432b38585ea 243 ble.stopAdvertising();
sigveseb 3:5432b38585ea 244 LOG_INFO("Stopped advertising.\n");
sigveseb 3:5432b38585ea 245 setState(DISCONNECTED);
sigveseb 3:5432b38585ea 246 } else {
sigveseb 3:5432b38585ea 247 LOG_WARN("Tried to stop advertising, but advertising is already stopped!\n");
sigveseb 3:5432b38585ea 248 }
sigveseb 3:5432b38585ea 249 }
sigveseb 3:5432b38585ea 250
aleksanb 16:fb8678ee25b0 251 /**
aleksanb 16:fb8678ee25b0 252 * @brief Extends the given gatt service with the given gatt characteristic.
aleksanb 16:fb8678ee25b0 253 * If the service doesn't exist, it is created.
aleksanb 16:fb8678ee25b0 254 *
aleksanb 16:fb8678ee25b0 255 * @param serviceUuid
aleksanb 16:fb8678ee25b0 256 UUID of the gatt service to be extended.
aleksanb 16:fb8678ee25b0 257 *
aleksanb 16:fb8678ee25b0 258 * @param characteristicUuid
aleksanb 16:fb8678ee25b0 259 * UUID to use for this characteristic.
aleksanb 16:fb8678ee25b0 260 *
aleksanb 16:fb8678ee25b0 261 * @param bytes
aleksanb 16:fb8678ee25b0 262 * Length in bytes of this characteristic's value.
aleksanb 16:fb8678ee25b0 263 *
aleksanb 16:fb8678ee25b0 264 * @param properties
aleksanb 16:fb8678ee25b0 265 * 8-bit bit field containing the characteristic's properties. See @ref ble_gatt_char_properties_t.
aleksanb 16:fb8678ee25b0 266 *
aleksanb 16:fb8678ee25b0 267 * @return Void.
aleksanb 16:fb8678ee25b0 268 */
sigveseb 3:5432b38585ea 269 void Puck::addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties) {
sigveseb 3:5432b38585ea 270 MBED_ASSERT(bytes <= 20);
sigveseb 3:5432b38585ea 271 uint16_t size = sizeof(uint8_t) * bytes;
sigveseb 3:5432b38585ea 272 uint8_t* value = (uint8_t*) malloc(size);
sigveseb 9:ba0527c6b6d0 273 if(value == NULL) {
sigveseb 9:ba0527c6b6d0 274 LOG_ERROR("Unable to malloc value for characteristic. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 275 }
sigveseb 9:ba0527c6b6d0 276
sigveseb 3:5432b38585ea 277 GattCharacteristic* characteristic = new GattCharacteristic(characteristicUuid, value, size, size, properties);
sigveseb 3:5432b38585ea 278 characteristics.push_back(characteristic);
sigveseb 9:ba0527c6b6d0 279
sigveseb 9:ba0527c6b6d0 280
sigveseb 3:5432b38585ea 281 GattService* service = NULL;
sigveseb 9:ba0527c6b6d0 282
sigveseb 3:5432b38585ea 283 int removeIndex = -1;
sigveseb 3:5432b38585ea 284 for(int i = 0; i < services.size(); i++) {
sigveseb 3:5432b38585ea 285 if(isEqualUUID(&services[i]->getUUID(), serviceUuid)) {
sigveseb 3:5432b38585ea 286 service = services[i];
sigveseb 3:5432b38585ea 287 removeIndex = i;
sigveseb 3:5432b38585ea 288 break;
sigveseb 3:5432b38585ea 289 }
sigveseb 3:5432b38585ea 290 }
sigveseb 3:5432b38585ea 291 GattCharacteristic** characteristics = NULL;
sigveseb 3:5432b38585ea 292 int characteristicsLength = 0;
sigveseb 3:5432b38585ea 293 if(service != NULL) {
sigveseb 3:5432b38585ea 294 characteristicsLength = service->getCharacteristicCount() + 1;
sigveseb 3:5432b38585ea 295 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
sigveseb 9:ba0527c6b6d0 296 if(characteristics == NULL) {
sigveseb 9:ba0527c6b6d0 297 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 298 }
sigveseb 3:5432b38585ea 299 for(int i = 0; i < characteristicsLength; i++) {
sigveseb 3:5432b38585ea 300 characteristics[i] = service->getCharacteristic(i);
sigveseb 3:5432b38585ea 301 }
sigveseb 3:5432b38585ea 302 services.erase(services.begin() + removeIndex);
sigveseb 3:5432b38585ea 303 delete service;
stiaje 4:91506772210d 304 free(previousCharacteristics);
sigveseb 3:5432b38585ea 305 } else {
sigveseb 3:5432b38585ea 306 characteristicsLength = 1;
sigveseb 3:5432b38585ea 307 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength);
sigveseb 9:ba0527c6b6d0 308 if(characteristics == NULL) {
sigveseb 9:ba0527c6b6d0 309 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 310 }
sigveseb 3:5432b38585ea 311 }
sigveseb 9:ba0527c6b6d0 312
sigveseb 3:5432b38585ea 313 characteristics[characteristicsLength - 1] = characteristic;
stiaje 4:91506772210d 314 previousCharacteristics = characteristics;
sigveseb 3:5432b38585ea 315 service = new GattService(serviceUuid, characteristics, characteristicsLength);
sigveseb 3:5432b38585ea 316 services.push_back(service);
sigveseb 9:ba0527c6b6d0 317 LOG_DEBUG("Added characteristic.\n");
sigveseb 3:5432b38585ea 318 }
sigveseb 3:5432b38585ea 319
stiaje 18:4c95a470d778 320
aleksanb 16:fb8678ee25b0 321 /**
aleksanb 16:fb8678ee25b0 322 * @brief Update the value of the given gatt characteristic.
aleksanb 16:fb8678ee25b0 323 *
aleksanb 16:fb8678ee25b0 324 * @param uuid
aleksanb 16:fb8678ee25b0 325 UUID of the gatt characteristic to be updated.
aleksanb 16:fb8678ee25b0 326 *
aleksanb 16:fb8678ee25b0 327 * @param value
aleksanb 16:fb8678ee25b0 328 * New value of the characteristic.
aleksanb 16:fb8678ee25b0 329 *
aleksanb 16:fb8678ee25b0 330 * @param length
aleksanb 16:fb8678ee25b0 331 * Length in bytes of the characteristic's value.
aleksanb 16:fb8678ee25b0 332 *
aleksanb 16:fb8678ee25b0 333 * @return Void.
aleksanb 16:fb8678ee25b0 334 */
sigveseb 8:49ffd38fb401 335 void Puck::updateCharacteristicValue(const UUID uuid, uint8_t* value, int length) {
sigveseb 8:49ffd38fb401 336 GattCharacteristic* characteristic = NULL;
aleksanb 14:9eda2d99fc1d 337 for(int i = 0; i < characteristics.size(); i++) {
aleksanb 14:9eda2d99fc1d 338 GattAttribute &gattAttribute = characteristics[i]->getValueAttribute();
aleksanb 14:9eda2d99fc1d 339 if(isEqualUUID(&gattAttribute.getUUID(), uuid)) {
sigveseb 8:49ffd38fb401 340 characteristic = characteristics[i];
aleksanb 14:9eda2d99fc1d 341 break;
aleksanb 14:9eda2d99fc1d 342 }
sigveseb 8:49ffd38fb401 343 }
sigveseb 8:49ffd38fb401 344 if(characteristic != NULL) {
aleksanb 14:9eda2d99fc1d 345 ble.updateCharacteristicValue(characteristic->getValueHandle(), value, length);
sigveseb 8:49ffd38fb401 346 LOG_VERBOSE("Updated characteristic value.\n");
sigveseb 8:49ffd38fb401 347 } else {
sigveseb 8:49ffd38fb401 348 LOG_WARN("Tried to update an unkown characteristic!\n");
sigveseb 8:49ffd38fb401 349 }
sigveseb 8:49ffd38fb401 350 }
sigveseb 8:49ffd38fb401 351
aleksanb 16:fb8678ee25b0 352 /**
aleksanb 16:fb8678ee25b0 353 * @brief Pass control to the bluetooth stack, executing pending callbacks afterwards. Should be used inside a while condition loop.
aleksanb 16:fb8678ee25b0 354 *
aleksanb 16:fb8678ee25b0 355 * Example:
aleksanb 16:fb8678ee25b0 356 * @code
aleksanb 17:23a05bd2fe2b 357 * while (puck->drive()) {
aleksanb 16:fb8678ee25b0 358 * // Do stuff
aleksanb 16:fb8678ee25b0 359 * }
aleksanb 16:fb8678ee25b0 360 * @endcode
aleksanb 16:fb8678ee25b0 361 *
aleksanb 16:fb8678ee25b0 362 * @return true.
aleksanb 16:fb8678ee25b0 363 *
aleksanb 16:fb8678ee25b0 364 */
sigveseb 3:5432b38585ea 365 bool Puck::drive() {
aleksanb 14:9eda2d99fc1d 366 if(state == DISCONNECTED) {
aleksanb 14:9eda2d99fc1d 367 startAdvertising();
aleksanb 14:9eda2d99fc1d 368 }
aleksanb 14:9eda2d99fc1d 369
sigveseb 3:5432b38585ea 370 ble.waitForEvent();
aleksanb 14:9eda2d99fc1d 371
sigveseb 3:5432b38585ea 372 while(pendingCallbackStack.size() > 0) {
sigveseb 15:bfc682889c15 373 pendingCallbackStack.back()(pendingCallbackParameterDataStack.back(), pendingCallbackParameterLengthStack.back());
sigveseb 3:5432b38585ea 374 pendingCallbackStack.pop_back();
sigveseb 15:bfc682889c15 375 pendingCallbackParameterDataStack.pop_back();
sigveseb 15:bfc682889c15 376 pendingCallbackParameterLengthStack.pop_back();
sigveseb 3:5432b38585ea 377 }
sigveseb 3:5432b38585ea 378 return true;
sigveseb 3:5432b38585ea 379 }
sigveseb 3:5432b38585ea 380
aleksanb 16:fb8678ee25b0 381 /**
aleksanb 16:fb8678ee25b0 382 * @brief Register callback to be triggered on characteristic write.
aleksanb 16:fb8678ee25b0 383 *
aleksanb 16:fb8678ee25b0 384 * @parameter uuid
aleksanb 16:fb8678ee25b0 385 * UUID of the gatt characteristic to bind callback to.
aleksanb 16:fb8678ee25b0 386 *
aleksanb 16:fb8678ee25b0 387 * @parameter callback
aleksanb 16:fb8678ee25b0 388 * CharacteristicWriteCallback to be executed on characteristic write.
aleksanb 16:fb8678ee25b0 389 *
aleksanb 16:fb8678ee25b0 390 * @return Void.
aleksanb 16:fb8678ee25b0 391 *
aleksanb 16:fb8678ee25b0 392 */
sigveseb 9:ba0527c6b6d0 393 void Puck::onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback) {
sigveseb 3:5432b38585ea 394 CharacteristicWriteCallbacks* cb = NULL;
sigveseb 3:5432b38585ea 395 for(int i = 0; i< writeCallbacks.size(); i++) {
sigveseb 9:ba0527c6b6d0 396 if(isEqualUUID(writeCallbacks[i]->uuid, *uuid)) {
sigveseb 3:5432b38585ea 397 cb = writeCallbacks[i];
sigveseb 3:5432b38585ea 398 break;
sigveseb 3:5432b38585ea 399 }
sigveseb 3:5432b38585ea 400 }
sigveseb 3:5432b38585ea 401 if(cb == NULL) {
sigveseb 3:5432b38585ea 402 cb = (CharacteristicWriteCallbacks*) malloc(sizeof(CharacteristicWriteCallbacks));
sigveseb 9:ba0527c6b6d0 403 if(cb == NULL) {
sigveseb 9:ba0527c6b6d0 404 LOG_ERROR("Could not malloc CharacteristicWriteCallbacks container. Possibly out of memory!\n");
sigveseb 9:ba0527c6b6d0 405 }
sigveseb 9:ba0527c6b6d0 406 cb->uuid = uuid;
sigveseb 3:5432b38585ea 407 cb->callbacks = new std::vector<CharacteristicWriteCallback>();
sigveseb 3:5432b38585ea 408 writeCallbacks.push_back(cb);
sigveseb 3:5432b38585ea 409 }
sigveseb 3:5432b38585ea 410 cb->callbacks->push_back(callback);
sigveseb 3:5432b38585ea 411 LOG_VERBOSE("Bound characteristic write callback (uuid: %x, callback: %x)\n", uuid, callback);
sigveseb 3:5432b38585ea 412 }
sigveseb 3:5432b38585ea 413
aleksanb 16:fb8678ee25b0 414 /**
aleksanb 16:fb8678ee25b0 415 * @brief Returns current value of provided gatt characteristic.
aleksanb 16:fb8678ee25b0 416 *
aleksanb 16:fb8678ee25b0 417 */
sigveseb 3:5432b38585ea 418 uint8_t* Puck::getCharacteristicValue(const UUID uuid) {
sigveseb 3:5432b38585ea 419 LOG_VERBOSE("Reading characteristic value for UUID %x\n", uuid);
sigveseb 3:5432b38585ea 420 for(int i = 0; i < characteristics.size(); i++) {
aleksanb 14:9eda2d99fc1d 421 GattAttribute &gattAttribute = characteristics[i]->getValueAttribute();
aleksanb 14:9eda2d99fc1d 422 if(isEqualUUID(&gattAttribute.getUUID(), uuid)) {
aleksanb 14:9eda2d99fc1d 423 return gattAttribute.getValuePtr();
sigveseb 3:5432b38585ea 424 }
sigveseb 3:5432b38585ea 425 }
sigveseb 3:5432b38585ea 426 LOG_WARN("Tried to read an unknown characteristic!");
sigveseb 3:5432b38585ea 427 return NULL;
sigveseb 3:5432b38585ea 428 }
sigveseb 3:5432b38585ea 429
aleksanb 16:fb8678ee25b0 430 /**
aleksanb 16:fb8678ee25b0 431 * @brief For internal use only. Exposed to hack around mbed framework limitation.
aleksanb 16:fb8678ee25b0 432 *
aleksanb 16:fb8678ee25b0 433 */
sigveseb 15:bfc682889c15 434 void Puck::onDataWritten(GattAttribute::Handle_t handle, const uint8_t* data, uint8_t length) {
sigveseb 3:5432b38585ea 435 for (int i = 0; i < characteristics.size(); i++) {
sigveseb 3:5432b38585ea 436 GattCharacteristic* characteristic = characteristics[i];
aleksanb 14:9eda2d99fc1d 437
aleksanb 14:9eda2d99fc1d 438 if (characteristic->getValueHandle() == handle) {
aleksanb 14:9eda2d99fc1d 439 GattAttribute &gattAttribute = characteristic->getValueAttribute();
aleksanb 14:9eda2d99fc1d 440
sigveseb 3:5432b38585ea 441 for(int j = 0; j < writeCallbacks.size(); j++) {
sigveseb 3:5432b38585ea 442 CharacteristicWriteCallbacks* characteristicWriteCallbacks = writeCallbacks[j];
aleksanb 14:9eda2d99fc1d 443
aleksanb 14:9eda2d99fc1d 444 if(isEqualUUID(characteristicWriteCallbacks->uuid, gattAttribute.getUUID())) {
sigveseb 3:5432b38585ea 445 for(int k = 0; k < characteristicWriteCallbacks->callbacks->size(); k++) {
sigveseb 3:5432b38585ea 446 pendingCallbackStack.push_back(characteristicWriteCallbacks->callbacks->at(k));
sigveseb 15:bfc682889c15 447
sigveseb 15:bfc682889c15 448 pendingCallbackParameterDataStack.push_back(data);
sigveseb 15:bfc682889c15 449 pendingCallbackParameterLengthStack.push_back(length);
sigveseb 3:5432b38585ea 450 }
sigveseb 9:ba0527c6b6d0 451 return;
sigveseb 3:5432b38585ea 452 }
sigveseb 3:5432b38585ea 453 }
sigveseb 3:5432b38585ea 454 }
sigveseb 3:5432b38585ea 455 }
sigveseb 3:5432b38585ea 456 }
sigveseb 3:5432b38585ea 457
sigveseb 3:5432b38585ea 458
sigveseb 3:5432b38585ea 459 #endif // __PUCK_HPP__