SimpleBLE example for mbed OS 5
Dependents: SimpleBLE-Example-mbedos5
Fork of SimpleBLE by
Diff: SimpleBLE.h
- Revision:
- 0:2ecd71f6ab04
- Child:
- 1:17c8f5afa7bc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SimpleBLE.h Wed May 11 12:59:14 2016 +0000 @@ -0,0 +1,385 @@ +/** + * Because BLE_API is too hard + */ +#include <string> +#include <sstream> +#include <vector> +#include <map> +#include "ble/BLE.h" + +using namespace std; + +/** + * Class so we can call onDataWritten on any SimpleCharInternal regardless of <T,U> + */ +class Updatable { +public: + virtual void onDataWritten(const uint8_t* data, size_t len) = 0; +}; + +/** + * Class that we wrap in SimpleChar so we can just implement operators, + * without having to type the full type of U when using this code. + * Whenever we get 'auto' we can get rid of this. + */ +template <class T> +class SimpleCharBase { +public: + virtual void update(T newValue) = 0; + virtual T* getValue(void) = 0; +}; + +/** + * Actual implementation of the char + * T is the underlying type, U is the GattCharacteristic it's wrapping + */ +template <class T, template <typename T2> class U> +class SimpleCharInternal : public Updatable, public SimpleCharBase<T> { +public: + SimpleCharInternal(BLE* aBle, + const UUID &uuid, + GattCharacteristic::Properties_t aGattChar, + T aDefaultValue, + void(*aCallback)(T) = NULL) : + ble(aBle), value(new T(aDefaultValue)), callback(aCallback) + { + state = new U<T>(uuid, value, aGattChar); + } + + ~SimpleCharInternal() { + if (state) { + free(state); + } + if (value) { + free(value); + } + } + + virtual void update(T newValue) { + *value = newValue; + ble->gattServer().write(state->getValueHandle(), (uint8_t *)value, sizeof(T)); + } + + U<T>* getChar(void) { + return state; + } + + virtual T* getValue(void) { + return value; + } + + virtual void onDataWritten(const uint8_t* data, size_t len) { + *value = ((T*)data)[0]; + if (callback) { + callback(*value); + } + } + +private: + BLE* ble; + T* value; + U<T>* state; + void(*callback)(T); +}; + +/** + * This is what the user gets back. it's nice and short so don't have to type much. + * If we get 'auto' we can get rid of this. + */ +template <class T> +class SimpleChar { +public: + SimpleChar(SimpleCharBase<T>* aBase) : base(aBase) { + } + ~SimpleChar() { + if (base) { + delete base; + } + } + + T operator=(const T& newValue) { + base->update(newValue); + return newValue; + }; + operator T() const { + return *(base->getValue()); + }; + +private: + SimpleCharBase<T>* base; +}; + + +class SimpleBLE { +public: + SimpleBLE(const char* aName, uint16_t aInterval = 1000) : name(aName), interval(aInterval) { + ble = &BLE::Instance(); + } + ~SimpleBLE() {} + + void start() { + ble->init(this, &SimpleBLE::bleInitComplete); + + /* SpinWait for initialization to complete. This is necessary because the + * BLE object is used in the main loop below. */ + while (ble->hasInitialized() == false) { /* spin loop */ } + } + + // Start up the BLE service and just run with it! + void waitForEvent() { + ble->waitForEvent(); + } + + // === START READONLY === + + template <typename T> + SimpleChar<T> readOnly(uint16_t serviceUuid, + const UUID& charUuid, + bool enableNotify = true, + T defaultValue = T()) { + GattCharacteristic::Properties_t gattChar = enableNotify ? + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; + + SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c = + new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue); + + addToServices(serviceUuid, c->getChar()); + + return *(new SimpleChar<T>(c)); + } + + template <typename T> + SimpleChar<T> readOnly(const char* serviceUuid, + const UUID& charUuid, + bool enableNotify = true, + T defaultValue = T()) { + GattCharacteristic::Properties_t gattChar = enableNotify ? + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; + + SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c = + new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue); + + addToServices(serviceUuid, c->getChar()); + + return *(new SimpleChar<T>(c)); + } + + // === END READONLY === + + // === START READWRITE === + + template <typename T> + SimpleChar<T> readWrite(uint16_t serviceUuid, + const UUID& charUuid, + bool enableNotify = true, + T defaultValue = T(), + void(*callback)(T) = NULL) { + GattCharacteristic::Properties_t gattChar = enableNotify ? + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; + + SimpleCharInternal<T, ReadWriteGattCharacteristic>* c = + new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback); + + addToServices(serviceUuid, c->getChar()); + + writeCallbacks[c->getChar()] = c; + + return *(new SimpleChar<T>(c)); + } + + + + template <typename T> + SimpleChar<T> readWrite(const char* serviceUuid, + const UUID& charUuid, + bool enableNotify = true, + T defaultValue = T(), + void(*callback)(T) = NULL) { + GattCharacteristic::Properties_t gattChar = enableNotify ? + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; + + SimpleCharInternal<T, ReadWriteGattCharacteristic>* c = + new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback); + + addToServices(serviceUuid, c->getChar()); + + writeCallbacks[c->getChar()] = c; + + return *(new SimpleChar<T>(c)); + } + + template <typename T> + SimpleChar<T> readWrite(uint16_t serviceUuid, + const UUID& charUuid, + void(*callback)(T) = NULL) { + return readWrite(serviceUuid, charUuid, true, T(), callback); + } + + template <typename T> + SimpleChar<T> readWrite(const char* serviceUuid, + const UUID& charUuid, + void(*callback)(T) = NULL) { + return readWrite(serviceUuid, charUuid, true, T(), callback); + } + + // === END READWRITE === + + // === START WRITEONLY === + + template <typename T> + SimpleChar<T> writeOnly(uint16_t serviceUuid, + const UUID& charUuid, + void(*callback)(T) = NULL) { + GattCharacteristic::Properties_t gattChar = enableNotify ? + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ; + + SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c = + new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, defaultValue, callback); + + addToServices(serviceUuid, c->getChar()); + + writeCallbacks[c->getChar()] = c; + + return *(new SimpleChar<T>(c)); + } + + template <typename T> + SimpleChar<T> writeOnly(const char* serviceUuid, + const UUID& charUuid, + void(*callback)(T) = NULL) { + + SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c = + new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, defaultValue, callback); + + addToServices(serviceUuid, c->getChar()); + + writeCallbacks[c->getChar()] = c; + + return *(new SimpleChar<T>(c)); + } + + // === END READWRITE === + + + void onDisconnection(Gap::DisconnectionEventCallback_t callback) { + ble->gap().onDisconnection(callback); + } + + void onConnection(Gap::ConnectionEventCallback_t callback) { + ble->gap().onConnection(callback); + } + + BLE* getBle(void) { + return ble; + } + + +private: + void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) + { + printf("bleInitComplete\r\n"); + + BLE& ble = params->ble; + ble_error_t error = params->error; + + if (error != BLE_ERROR_NONE) { + printf("BLE Init error %d\r\n", error); + return; + } + + /* Ensure that it is the default instance of BLE */ + if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { + return; + } + + ble.gattServer().onDataWritten(this, &SimpleBLE::onDataWrittenCallback); + + // let's add some services yo (why is there no 'auto' in mbed?) + uint16_t uuid16_list[uint16_services.size()]; + size_t uuid16_counter = 0; + { + typedef std::map<uint16_t, vector<GattCharacteristic*>* >::iterator it_type; + for(it_type it = uint16_services.begin(); it != uint16_services.end(); it++) { + printf("Creating service 0x%x\n", it->first); + uuid16_list[uuid16_counter++] = it->first; + + GattCharacteristic* charTable[it->second->size()]; + for (size_t git = 0; git < it->second->size(); git++) { + charTable[git] = it->second->at(git); + } + + GattService service(it->first, charTable, it->second->size()); + ble.gattServer().addService(service); + } + } + + // 128 Bit services + const char* uuid128_list[uint128_services.size()]; + size_t uuid128_counter = 0; + { + typedef std::map<string, vector<GattCharacteristic*>* >::iterator it_type; + for(it_type it = uint128_services.begin(); it != uint128_services.end(); it++) { + printf("Creating service %s\n", it->first.c_str()); + uuid128_list[uuid128_counter++] = it->first.c_str(); + + GattCharacteristic* charTable[it->second->size()]; + for (size_t git = 0; git < it->second->size(); git++) { + charTable[git] = it->second->at(git); + } + + GattService service(UUID(it->first.c_str()), charTable, it->second->size()); + ble.gattServer().addService(service); + } + } + + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, uuid16_counter); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid128_list, uuid128_counter); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)name, strlen(name)); + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(interval); + ble.gap().startAdvertising(); + + printf("Started advertising\r\n"); + } + + void onDataWrittenCallback(const GattWriteCallbackParams *params) { + // see if we know for which char this message is... + typedef std::map<GattCharacteristic*, Updatable* >::iterator it_type; + for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) { + if (it->first->getValueHandle() == params->handle) { + it->second->onDataWritten(params->data, params->len); + } + } + } + + void addToServices(uint16_t uuid, GattCharacteristic* c) { + if (uint16_services.count(uuid) == 0) { + uint16_services[uuid] = new vector<GattCharacteristic*>(); + } + + uint16_services[uuid]->push_back(c); + } + + void addToServices(const char* aUuid, GattCharacteristic* c) { + string uuid(aUuid); + if (uint128_services.count(uuid) == 0) { + uint128_services[uuid] = new vector<GattCharacteristic*>(); + } + + uint128_services[uuid]->push_back(c); + } + + BLE* ble; + const char* name; + uint16_t interval; + map<uint16_t, vector<GattCharacteristic*>* > uint16_services; + map<string, vector<GattCharacteristic*>* > uint128_services; + map<GattCharacteristic*, Updatable*> writeCallbacks; +}; +