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