Update for latest nRF51822 code changes.

Dependencies:   BLE_API nRF51822

Fork of Puck by Nordic Pucks

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__