Abraham Marsen / Mbed 2 deprecated Jazz_Hands_Nordic

Dependencies:   mbed

Committer:
Grimmkey
Date:
Thu Apr 30 20:46:27 2015 +0000
Revision:
0:b8221deeaa87
Georgia Institute of Technology ECE 4180 Spring 2015 Jazz Hands project, Nordic nRF51822 half

Who changed what in which revision?

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