Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SimpleBLE.h
00001 /* 00002 * Copyright (c) 2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * 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, WITHOUT 00012 * 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 #include <string> 00018 #include <sstream> 00019 #include <vector> 00020 #include <map> 00021 #include "ble/BLE.h" 00022 00023 #define def_fn(T, postfix) \ 00024 SimpleChar<T> readOnly_##postfix \ 00025 (uint16_t serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T()) { \ 00026 return readOnly<T>(serviceUuid, charUuid, enableNotify, defaultValue); \ 00027 }\ 00028 SimpleChar<T> readOnly_##postfix \ 00029 (const char* serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T()) { \ 00030 return readOnly<T>(serviceUuid, charUuid, enableNotify, defaultValue); \ 00031 }\ 00032 \ 00033 SimpleChar<T> readWrite_##postfix \ 00034 (uint16_t serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T(), void(*callback)(T) = NULL) { \ 00035 return readWrite<T>(serviceUuid, charUuid, enableNotify, defaultValue, callback); \ 00036 }\ 00037 SimpleChar<T> readWrite_##postfix \ 00038 (const char* serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T(), void(*callback)(T) = NULL) { \ 00039 return readWrite<T>(serviceUuid, charUuid, enableNotify, defaultValue, callback); \ 00040 }\ 00041 SimpleChar<T> readWrite_##postfix \ 00042 (uint16_t serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \ 00043 return readWrite<T>(serviceUuid, charUuid, callback); \ 00044 }\ 00045 SimpleChar<T> readWrite_##postfix \ 00046 (const char* serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \ 00047 return readWrite<T>(serviceUuid, charUuid, callback); \ 00048 }\ 00049 \ 00050 SimpleChar<T> writeOnly_##postfix \ 00051 (uint16_t serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \ 00052 return writeOnly<T>(serviceUuid, charUuid, callback); \ 00053 }\ 00054 SimpleChar<T> writeOnly_##postfix \ 00055 (const char* serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \ 00056 return writeOnly<T>(serviceUuid, charUuid, callback); \ 00057 } 00058 00059 using namespace std; 00060 00061 /** 00062 * Class so we can call onDataWritten on any SimpleCharInternal regardless of <T,U> 00063 */ 00064 class Updatable { 00065 public: 00066 virtual void onDataWritten(const uint8_t* data, size_t len) = 0; 00067 }; 00068 00069 /** 00070 * Class that we wrap in SimpleChar so we can just implement operators, 00071 * without having to type the full type of U when using this code. 00072 * Whenever we get 'auto' we can get rid of this. 00073 */ 00074 template <class T> 00075 class SimpleCharBase { 00076 public: 00077 virtual void update(T newValue) = 0; 00078 virtual T* getValue(void) = 0; 00079 }; 00080 00081 /** 00082 * Actual implementation of the char 00083 * T is the underlying type, U is the GattCharacteristic it's wrapping 00084 */ 00085 template <class T, template <typename T2> class U> 00086 class SimpleCharInternal : public Updatable, public SimpleCharBase<T> { 00087 public: 00088 SimpleCharInternal(BLE* aBle, 00089 const UUID &uuid, 00090 GattCharacteristic::Properties_t aGattChar, 00091 T aDefaultValue, 00092 void(*aCallback)(T) = NULL) : 00093 ble(aBle), value(new T(aDefaultValue)), callback(aCallback) 00094 { 00095 state = new U<T>(uuid, value, aGattChar); 00096 } 00097 00098 ~SimpleCharInternal() { 00099 if (state) { 00100 free(state); 00101 } 00102 if (value) { 00103 free(value); 00104 } 00105 } 00106 00107 virtual void update(T newValue) { 00108 *value = newValue; 00109 ble->gattServer().write(state->getValueHandle(), (uint8_t *)value, sizeof(T)); 00110 } 00111 00112 U<T>* getChar(void) { 00113 return state; 00114 } 00115 00116 virtual T* getValue(void) { 00117 return value; 00118 } 00119 00120 virtual void onDataWritten(const uint8_t* data, size_t len) { 00121 *value = ((T*)data)[0]; 00122 if (callback) { 00123 callback(*value); 00124 } 00125 } 00126 00127 private: 00128 BLE* ble; 00129 T* value; 00130 U<T>* state; 00131 void(*callback)(T); 00132 }; 00133 00134 /** 00135 * This is what the user gets back. it's nice and short so don't have to type much. 00136 * If we get 'auto' we can get rid of this. 00137 */ 00138 template <class T> 00139 class SimpleChar { 00140 public: 00141 SimpleChar(SimpleCharBase<T>* aBase) : base(aBase) { 00142 } 00143 ~SimpleChar() { 00144 if (base) { 00145 delete base; 00146 } 00147 } 00148 00149 T operator=(const T& newValue) { 00150 base->update(newValue); 00151 return newValue; 00152 }; 00153 operator T() const { 00154 return *(base->getValue()); 00155 }; 00156 00157 private: 00158 SimpleCharBase<T>* base; 00159 }; 00160 00161 00162 class SimpleBLE { 00163 public: 00164 SimpleBLE(const char* aName, uint16_t aInterval = 1000, bool aLogging = true) 00165 : name(aName), interval(aInterval), logging(aLogging) 00166 { 00167 ble = &BLE::Instance(); 00168 } 00169 ~SimpleBLE() {} 00170 00171 void start() { 00172 ble->init(this, &SimpleBLE::bleInitComplete); 00173 00174 /* SpinWait for initialization to complete. This is necessary because the 00175 * BLE object is used in the main loop below. */ 00176 while (ble->hasInitialized() == false) { /* spin loop */ } 00177 } 00178 00179 // Start up the BLE service and just run with it! 00180 void waitForEvent() { 00181 ble->waitForEvent(); 00182 } 00183 00184 void onDisconnection(Gap::DisconnectionEventCallback_t callback) { 00185 ble->gap().onDisconnection(callback); 00186 } 00187 00188 void onConnection(Gap::ConnectionEventCallback_t callback) { 00189 ble->gap().onConnection(callback); 00190 } 00191 00192 BLE* getBle(void) { 00193 return ble; 00194 } 00195 00196 def_fn(uint8_t, u8) 00197 def_fn(uint16_t, u16) 00198 def_fn(uint32_t, u32) 00199 def_fn(int8_t, i8) 00200 def_fn(int16_t, i16) 00201 def_fn(int32_t, i32) 00202 def_fn(bool, bool) 00203 def_fn(float, float) 00204 00205 private: 00206 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 00207 { 00208 if (logging) printf("bleInitComplete\r\n"); 00209 00210 BLE& ble = params->ble; 00211 ble_error_t error = params->error; 00212 00213 if (error != BLE_ERROR_NONE) { 00214 if (logging) printf("BLE Init error %d\r\n", error); 00215 return; 00216 } 00217 00218 /* Ensure that it is the default instance of BLE */ 00219 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 00220 return; 00221 } 00222 00223 ble.gattServer().onDataWritten(this, &SimpleBLE::onDataWrittenCallback); 00224 00225 // let's add some services yo (why is there no 'auto' in mbed?) 00226 uint16_t uuid16_list[uint16_services.size()]; 00227 size_t uuid16_counter = 0; 00228 { 00229 typedef std::map<uint16_t, vector<GattCharacteristic*>* >::iterator it_type; 00230 for(it_type it = uint16_services.begin(); it != uint16_services.end(); it++) { 00231 if (logging) printf("Creating service 0x%x\n", it->first); 00232 uuid16_list[uuid16_counter++] = it->first; 00233 00234 GattCharacteristic* charTable[it->second->size()]; 00235 for (size_t git = 0; git < it->second->size(); git++) { 00236 charTable[git] = it->second->at(git); 00237 } 00238 00239 GattService service(it->first, charTable, it->second->size()); 00240 ble.gattServer().addService(service); 00241 } 00242 } 00243 00244 // 128 Bit services 00245 const char* uuid128_list[uint128_services.size()]; 00246 size_t uuid128_counter = 0; 00247 { 00248 typedef std::map<string, vector<GattCharacteristic*>* >::iterator it_type; 00249 for(it_type it = uint128_services.begin(); it != uint128_services.end(); it++) { 00250 if (logging) printf("Creating service %s\n", it->first.c_str()); 00251 uuid128_list[uuid128_counter++] = it->first.c_str(); 00252 00253 GattCharacteristic* charTable[it->second->size()]; 00254 for (size_t git = 0; git < it->second->size(); git++) { 00255 charTable[git] = it->second->at(git); 00256 } 00257 00258 GattService service(UUID(it->first.c_str()), charTable, it->second->size()); 00259 ble.gattServer().addService(service); 00260 } 00261 } 00262 00263 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00264 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, uuid16_counter); 00265 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid128_list, uuid128_counter); 00266 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)name, strlen(name)); 00267 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00268 ble.gap().setAdvertisingInterval(interval); 00269 ble.gap().startAdvertising(); 00270 00271 if (logging) printf("Started advertising\r\n"); 00272 } 00273 00274 void onDataWrittenCallback(const GattWriteCallbackParams *params) { 00275 // see if we know for which char this message is... 00276 typedef std::map<GattCharacteristic*, Updatable* >::iterator it_type; 00277 for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) { 00278 if (it->first->getValueHandle() == params->handle) { 00279 it->second->onDataWritten(params->data, params->len); 00280 } 00281 } 00282 } 00283 00284 void addToServices(uint16_t uuid, GattCharacteristic* c) { 00285 if (uint16_services.count(uuid) == 0) { 00286 uint16_services[uuid] = new vector<GattCharacteristic*>(); 00287 } 00288 00289 uint16_services[uuid]->push_back(c); 00290 } 00291 00292 void addToServices(const char* aUuid, GattCharacteristic* c) { 00293 string uuid(aUuid); 00294 if (uint128_services.count(uuid) == 0) { 00295 uint128_services[uuid] = new vector<GattCharacteristic*>(); 00296 } 00297 00298 uint128_services[uuid]->push_back(c); 00299 } 00300 00301 // === START READONLY === 00302 00303 template <typename T> 00304 SimpleChar<T> readOnly(uint16_t serviceUuid, 00305 const UUID& charUuid, 00306 bool enableNotify = true, 00307 T defaultValue = T()) { 00308 GattCharacteristic::Properties_t gattChar = enableNotify ? 00309 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : 00310 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; 00311 00312 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c = 00313 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue); 00314 00315 addToServices(serviceUuid, c->getChar()); 00316 00317 return *(new SimpleChar<T>(c)); 00318 } 00319 00320 template <typename T> 00321 SimpleChar<T> readOnly(const char* serviceUuid, 00322 const UUID& charUuid, 00323 bool enableNotify = true, 00324 T defaultValue = T()) { 00325 GattCharacteristic::Properties_t gattChar = enableNotify ? 00326 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : 00327 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; 00328 00329 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c = 00330 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue); 00331 00332 addToServices(serviceUuid, c->getChar()); 00333 00334 return *(new SimpleChar<T>(c)); 00335 } 00336 00337 // === END READONLY === 00338 00339 // === START READWRITE === 00340 00341 template <typename T> 00342 SimpleChar<T> readWrite(uint16_t serviceUuid, 00343 const UUID& charUuid, 00344 bool enableNotify = true, 00345 T defaultValue = T(), 00346 void(*callback)(T) = NULL) { 00347 GattCharacteristic::Properties_t gattChar = enableNotify ? 00348 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : 00349 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; 00350 00351 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c = 00352 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback); 00353 00354 addToServices(serviceUuid, c->getChar()); 00355 00356 writeCallbacks[c->getChar()] = c; 00357 00358 return *(new SimpleChar<T>(c)); 00359 } 00360 00361 00362 00363 template <typename T> 00364 SimpleChar<T> readWrite(const char* serviceUuid, 00365 const UUID& charUuid, 00366 bool enableNotify = true, 00367 T defaultValue = T(), 00368 void(*callback)(T) = NULL) { 00369 GattCharacteristic::Properties_t gattChar = enableNotify ? 00370 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : 00371 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; 00372 00373 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c = 00374 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback); 00375 00376 addToServices(serviceUuid, c->getChar()); 00377 00378 writeCallbacks[c->getChar()] = c; 00379 00380 return *(new SimpleChar<T>(c)); 00381 } 00382 00383 template <typename T> 00384 SimpleChar<T> readWrite(uint16_t serviceUuid, 00385 const UUID& charUuid, 00386 void(*callback)(T) = NULL) { 00387 return readWrite(serviceUuid, charUuid, true, T(), callback); 00388 } 00389 00390 template <typename T> 00391 SimpleChar<T> readWrite(const char* serviceUuid, 00392 const UUID& charUuid, 00393 void(*callback)(T) = NULL) { 00394 return readWrite(serviceUuid, charUuid, true, T(), callback); 00395 } 00396 00397 // === END READWRITE === 00398 00399 // === START WRITEONLY === 00400 00401 template <typename T> 00402 SimpleChar<T> writeOnly(uint16_t serviceUuid, 00403 const UUID& charUuid, 00404 void(*callback)(T) = NULL) { 00405 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c = 00406 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback); 00407 00408 addToServices(serviceUuid, c->getChar()); 00409 00410 writeCallbacks[c->getChar()] = c; 00411 00412 return *(new SimpleChar<T>(c)); 00413 } 00414 00415 template <typename T> 00416 SimpleChar<T> writeOnly(const char* serviceUuid, 00417 const UUID& charUuid, 00418 void(*callback)(T) = NULL) { 00419 00420 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c = 00421 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback); 00422 00423 addToServices(serviceUuid, c->getChar()); 00424 00425 writeCallbacks[c->getChar()] = c; 00426 00427 return *(new SimpleChar<T>(c)); 00428 } 00429 00430 // === END WRITEONLY === 00431 00432 BLE* ble; 00433 const char* name; 00434 uint16_t interval; 00435 bool logging; 00436 map<uint16_t, vector<GattCharacteristic*>* > uint16_services; 00437 map<string, vector<GattCharacteristic*>* > uint128_services; 00438 map<GattCharacteristic*, Updatable*> writeCallbacks; 00439 }; 00440
Generated on Fri Jul 15 2022 03:48:31 by
1.7.2