mbed-x / SimpleBLE-mbed-os-5

Dependents:   SimpleBLE-Example-mbedos5

Fork of SimpleBLE by mbed-x

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SimpleBLE.h Source File

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