-
Dependencies: BLE_API nRF51822
Fork of Puck by
Puck.h
00001 /** 00002 * Copyright 2014 Nordic Semiconductor 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License 00015 */ 00016 00017 00018 #ifndef __PUCK_HPP__ 00019 #define __PUCK_HPP__ 00020 00021 #include "BLEDevice.h" 00022 #include "mbed.h" 00023 #include "Log.h" 00024 #include <vector> 00025 00026 enum PuckState { 00027 CONNECTING, 00028 CONNECTED, 00029 ADVERTISING, 00030 DISCONNECTED 00031 }; 00032 00033 const UUID stringToUUID(const char* str); 00034 00035 typedef void (*CharacteristicWriteCallback)(const uint8_t* value, uint8_t length); 00036 00037 typedef struct { 00038 const UUID* uuid; 00039 std::vector<CharacteristicWriteCallback>* callbacks; 00040 } CharacteristicWriteCallbacks; 00041 00042 00043 class Puck { 00044 private: 00045 Puck() {} 00046 Puck(const Puck&); 00047 Puck& operator=(const Puck&); 00048 00049 BLEDevice ble; 00050 uint8_t beaconPayload[25]; 00051 PuckState state; 00052 std::vector<GattService*> services; 00053 std::vector<GattCharacteristic*> characteristics; 00054 std::vector<CharacteristicWriteCallbacks*> writeCallbacks; 00055 std::vector<CharacteristicWriteCallback> pendingCallbackStack; 00056 std::vector<const uint8_t*> pendingCallbackParameterDataStack; 00057 std::vector<uint8_t> pendingCallbackParameterLengthStack; 00058 00059 GattCharacteristic **previousCharacteristics; 00060 00061 public: 00062 static Puck &getPuck(); 00063 00064 BLEDevice &getBle() { return ble; } 00065 PuckState getState() { return state; } 00066 void setState(PuckState state); 00067 void init(uint16_t minor); 00068 void startAdvertising(); 00069 void stopAdvertising(); 00070 void disconnect(); 00071 bool drive(); 00072 int countFreeMemory(); 00073 void onDataWritten(GattAttribute::Handle_t handle, const uint8_t* data, const uint8_t length); 00074 void addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties = 0xA); 00075 00076 void onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback); 00077 void updateCharacteristicValue(const UUID uuid, uint8_t* value, int length); 00078 00079 uint8_t* getCharacteristicValue(const UUID uuid); 00080 }; 00081 00082 Puck &Puck::getPuck() { 00083 static Puck _puckSingletonInstance; 00084 return _puckSingletonInstance; 00085 } 00086 00087 void onDisconnection(Gap::Handle_t handle, Gap::DisconnectionReason_t disconnectReason) { 00088 LOG_INFO("Disconnected.\n"); 00089 Puck::getPuck().setState(DISCONNECTED); 00090 } 00091 00092 void onConnection(Gap::Handle_t handle, 00093 Gap::addr_type_t peerAddrType, 00094 const Gap::address_t peerAddr, 00095 const Gap::ConnectionParams_t * connectionParams) { 00096 LOG_INFO("Connected.\n"); 00097 Puck::getPuck().setState(CONNECTED); 00098 } 00099 00100 void onDataWrittenCallback(const GattCharacteristicWriteCBParams *context) { 00101 Puck::getPuck().onDataWritten(context->charHandle, context->data, context->len); 00102 } 00103 00104 bool isEqualUUID(const UUID* uuidA, const UUID uuidB) { 00105 const uint8_t* uuidABase = uuidA->getBaseUUID(); 00106 const uint8_t* uuidBBase = uuidB.getBaseUUID(); 00107 00108 for(int i = 0; i < 16; i++) { 00109 if(uuidABase[i] != uuidBBase[i]) { 00110 return false; 00111 } 00112 } 00113 if(uuidA->getShortUUID() != uuidB.getShortUUID()) { 00114 return false; 00115 } 00116 return true; 00117 } 00118 00119 const UUID stringToUUID(const char* str) { 00120 uint8_t array[16]; 00121 for(int i = 0; i < 16; i++) { 00122 array[i] = str[i]; 00123 } 00124 return UUID(array); 00125 } 00126 00127 void Puck::disconnect() { 00128 ble.disconnect(Gap::LOCAL_HOST_TERMINATED_CONNECTION); 00129 } 00130 00131 int Puck::countFreeMemory() { 00132 int blocksize = 256; 00133 int amount = 0; 00134 while (blocksize > 0) { 00135 amount += blocksize; 00136 LOG_VERBOSE("Trying to malloc %i bytes... ", amount); 00137 char *p = (char *) malloc(amount); 00138 if (p == NULL) { 00139 LOG_VERBOSE("FAIL!\n", amount); 00140 amount -= blocksize; 00141 blocksize /= 2; 00142 } else { 00143 free(p); 00144 LOG_VERBOSE("OK!\n", amount); 00145 } 00146 } 00147 LOG_DEBUG("Free memory: %i bytes.\n", amount); 00148 return amount; 00149 } 00150 00151 void Puck::setState(PuckState state) { 00152 LOG_DEBUG("Changed state to %i\n", state); 00153 this->state = state; 00154 } 00155 00156 void Puck::init(uint16_t minor) { 00157 /* 00158 * The Beacon payload (encapsulated within the MSD advertising data structure) 00159 * has the following composition: 00160 * 128-Bit UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61 00161 * Major/Minor = 1337 / XXXX 00162 * Tx Power = C8 00163 */ 00164 uint8_t beaconPayloadTemplate[] = { 00165 0x00, 0x00, // Company identifier code (0x004C == Apple) 00166 0x02, // ID 00167 0x15, // length of the remaining payload 00168 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID 00169 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61, 00170 0x13, 0x37, // the major value to differenciate a location (Our app requires 1337 as major number) 00171 0x00, 0x00, // the minor value to differenciate a location (Change this to differentiate location pucks) 00172 0xC8 // 2's complement of the Tx power (-56dB) 00173 }; 00174 beaconPayloadTemplate[22] = minor >> 8; 00175 beaconPayloadTemplate[23] = minor & 255; 00176 00177 for (int i=0; i < 25; i++) { 00178 beaconPayload[i] = beaconPayloadTemplate[i]; 00179 } 00180 00181 ble.init(); 00182 LOG_DEBUG("Inited BLEDevice.\n"); 00183 setState(DISCONNECTED); 00184 00185 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); 00186 LOG_DEBUG("Accumulate advertising payload: BREDR_NOT_SUPPORTED.\n"); 00187 00188 ble.accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, beaconPayload, sizeof(beaconPayload)); 00189 LOG_DEBUG("Accumulate advertising payload: beacon data.\n"); 00190 00191 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00192 LOG_DEBUG("Setting advertising type: ADV_CONNECTABLE_UNDIRECTED.\n"); 00193 00194 int hundredMillisecondsInAdvertisingIntervalFormat = 160; 00195 ble.setAdvertisingInterval(hundredMillisecondsInAdvertisingIntervalFormat); 00196 LOG_DEBUG("Set advertising interval: 160 (100 ms).\n"); 00197 00198 ble.onDisconnection(onDisconnection); 00199 ble.onConnection(onConnection); 00200 ble.onDataWritten(onDataWrittenCallback); 00201 LOG_DEBUG("Hooked up internal event handlers.\n"); 00202 00203 for(int i = 0; i < services.size(); i++) { 00204 ble.addService(*services[i]); 00205 LOG_DEBUG("Added service %x to BLEDevice\n", services[i]); 00206 } 00207 00208 LOG_INFO("Inited puck as 0x%X.\n", minor); 00209 } 00210 00211 void Puck::startAdvertising() { 00212 ble.startAdvertising(); 00213 LOG_INFO("Starting to advertise.\n"); 00214 setState(ADVERTISING); 00215 } 00216 00217 void Puck::stopAdvertising() { 00218 if(state == ADVERTISING) { 00219 ble.stopAdvertising(); 00220 LOG_INFO("Stopped advertising.\n"); 00221 setState(DISCONNECTED); 00222 } else { 00223 LOG_WARN("Tried to stop advertising, but advertising is already stopped!\n"); 00224 } 00225 } 00226 00227 00228 void Puck::addCharacteristic(const UUID serviceUuid, const UUID characteristicUuid, int bytes, int properties) { 00229 MBED_ASSERT(bytes <= 20); 00230 uint16_t size = sizeof(uint8_t) * bytes; 00231 uint8_t* value = (uint8_t*) malloc(size); 00232 if(value == NULL) { 00233 LOG_ERROR("Unable to malloc value for characteristic. Possibly out of memory!\n"); 00234 } 00235 00236 GattCharacteristic* characteristic = new GattCharacteristic(characteristicUuid, value, size, size, properties); 00237 characteristics.push_back(characteristic); 00238 00239 00240 GattService* service = NULL; 00241 00242 int removeIndex = -1; 00243 for(int i = 0; i < services.size(); i++) { 00244 if(isEqualUUID(&services[i]->getUUID(), serviceUuid)) { 00245 service = services[i]; 00246 removeIndex = i; 00247 break; 00248 } 00249 } 00250 GattCharacteristic** characteristics = NULL; 00251 int characteristicsLength = 0; 00252 if(service != NULL) { 00253 characteristicsLength = service->getCharacteristicCount() + 1; 00254 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength); 00255 if(characteristics == NULL) { 00256 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n"); 00257 } 00258 for(int i = 0; i < characteristicsLength; i++) { 00259 characteristics[i] = service->getCharacteristic(i); 00260 } 00261 services.erase(services.begin() + removeIndex); 00262 delete service; 00263 free(previousCharacteristics); 00264 } else { 00265 characteristicsLength = 1; 00266 characteristics = (GattCharacteristic**) malloc(sizeof(GattCharacteristic*) * characteristicsLength); 00267 if(characteristics == NULL) { 00268 LOG_ERROR("Unable to malloc array of characteristics for service creation. Possibly out of memory!\n"); 00269 } 00270 } 00271 00272 characteristics[characteristicsLength - 1] = characteristic; 00273 previousCharacteristics = characteristics; 00274 service = new GattService(serviceUuid, characteristics, characteristicsLength); 00275 services.push_back(service); 00276 LOG_DEBUG("Added characteristic.\n"); 00277 } 00278 00279 void Puck::updateCharacteristicValue(const UUID uuid, uint8_t* value, int length) { 00280 GattCharacteristic* characteristic = NULL; 00281 for(int i = 0; i < characteristics.size(); i++) { 00282 GattAttribute &gattAttribute = characteristics[i]->getValueAttribute(); 00283 if(isEqualUUID(&gattAttribute.getUUID(), uuid)) { 00284 characteristic = characteristics[i]; 00285 break; 00286 } 00287 } 00288 if(characteristic != NULL) { 00289 ble.updateCharacteristicValue(characteristic->getValueHandle(), value, length); 00290 LOG_VERBOSE("Updated characteristic value.\n"); 00291 } else { 00292 LOG_WARN("Tried to update an unkown characteristic!\n"); 00293 } 00294 } 00295 00296 bool Puck::drive() { 00297 if(state == DISCONNECTED) { 00298 startAdvertising(); 00299 } 00300 00301 ble.waitForEvent(); 00302 00303 while(pendingCallbackStack.size() > 0) { 00304 pendingCallbackStack.back()(pendingCallbackParameterDataStack.back(), pendingCallbackParameterLengthStack.back()); 00305 pendingCallbackStack.pop_back(); 00306 pendingCallbackParameterDataStack.pop_back(); 00307 pendingCallbackParameterLengthStack.pop_back(); 00308 } 00309 return true; 00310 } 00311 00312 00313 void Puck::onCharacteristicWrite(const UUID* uuid, CharacteristicWriteCallback callback) { 00314 CharacteristicWriteCallbacks* cb = NULL; 00315 for(int i = 0; i< writeCallbacks.size(); i++) { 00316 if(isEqualUUID(writeCallbacks[i]->uuid, *uuid)) { 00317 cb = writeCallbacks[i]; 00318 break; 00319 } 00320 } 00321 if(cb == NULL) { 00322 cb = (CharacteristicWriteCallbacks*) malloc(sizeof(CharacteristicWriteCallbacks)); 00323 if(cb == NULL) { 00324 LOG_ERROR("Could not malloc CharacteristicWriteCallbacks container. Possibly out of memory!\n"); 00325 } 00326 cb->uuid = uuid; 00327 cb->callbacks = new std::vector<CharacteristicWriteCallback>(); 00328 writeCallbacks.push_back(cb); 00329 } 00330 cb->callbacks->push_back(callback); 00331 LOG_VERBOSE("Bound characteristic write callback (uuid: %x, callback: %x)\n", uuid, callback); 00332 } 00333 00334 00335 uint8_t* Puck::getCharacteristicValue(const UUID uuid) { 00336 LOG_VERBOSE("Reading characteristic value for UUID %x\n", uuid); 00337 for(int i = 0; i < characteristics.size(); i++) { 00338 GattAttribute &gattAttribute = characteristics[i]->getValueAttribute(); 00339 if(isEqualUUID(&gattAttribute.getUUID(), uuid)) { 00340 return gattAttribute.getValuePtr(); 00341 } 00342 } 00343 LOG_WARN("Tried to read an unknown characteristic!"); 00344 return NULL; 00345 } 00346 00347 00348 void Puck::onDataWritten(GattAttribute::Handle_t handle, const uint8_t* data, uint8_t length) { 00349 for (int i = 0; i < characteristics.size(); i++) { 00350 GattCharacteristic* characteristic = characteristics[i]; 00351 00352 if (characteristic->getValueHandle() == handle) { 00353 GattAttribute &gattAttribute = characteristic->getValueAttribute(); 00354 00355 for(int j = 0; j < writeCallbacks.size(); j++) { 00356 CharacteristicWriteCallbacks* characteristicWriteCallbacks = writeCallbacks[j]; 00357 00358 if(isEqualUUID(characteristicWriteCallbacks->uuid, gattAttribute.getUUID())) { 00359 for(int k = 0; k < characteristicWriteCallbacks->callbacks->size(); k++) { 00360 pendingCallbackStack.push_back(characteristicWriteCallbacks->callbacks->at(k)); 00361 00362 pendingCallbackParameterDataStack.push_back(data); 00363 pendingCallbackParameterLengthStack.push_back(length); 00364 } 00365 return; 00366 } 00367 } 00368 } 00369 } 00370 } 00371 00372 00373 #endif // __PUCK_HPP__
Generated on Wed Jul 13 2022 04:31:21 by 1.7.2