Axel DREVON / SimpleBLE

Dependencies:   BLE_API

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 "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