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