SimpleBLE prototype

Dependencies:   BLE_API mbed nRF51822

SimpleBLE.h

Committer:
janjongboom
Date:
2016-05-11
Revision:
1:acae50e4bc88
Parent:
0:0c885d287f5a

File content as of revision 1:acae50e4bc88:

/**
 * Because BLE_API is too hard
 */
#include <string>
#include <vector>
#include <map>
#include "ble/BLE.h"

using namespace std;

template <class T>
class ReadOnlyCharacteristic {
public:
    ReadOnlyCharacteristic(BLE* aBle, const uint16_t aCharUuid, bool enableNotify, T defaultValue) :
        ble(aBle)
    {
        state = new ReadOnlyGattCharacteristic<T>(aCharUuid, new T(defaultValue), enableNotify ? 
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
    }
    
    ~ReadOnlyCharacteristic() {
        // @todo clear defaultValue
        if (state) {
            free(state);
        }
    }
    
    void update(T newValue) {
        ble->gattServer().write(state->getValueHandle(), (uint8_t *)&newValue, sizeof(T));
    }
    
    ReadOnlyGattCharacteristic<T>* getChar(void) {
        return state;
    }

private:
    BLE* ble;
    ReadOnlyGattCharacteristic<T>* state;
};

template <class T>
class ReadWriteCharacteristic {
public:
    ReadWriteCharacteristic(BLE* aBle, const uint16_t aCharUuid, bool enableNotify, T defaultValue) :
        ble(aBle)
    {
        state = new ReadWriteGattCharacteristic<T>(aCharUuid, new T(defaultValue), enableNotify ? 
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
            GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
    }
    
    ~ReadWriteCharacteristic() {
        // @todo clear defaultValue
        if (state) {
            free(state);
        }
    }
    
    void update(T newValue) {
        ble->gattServer().write(state->getValueHandle(), (uint8_t *)&newValue, sizeof(T));
    }
    
    ReadWriteGattCharacteristic<T>* getChar(void) {
        return state;
    }

private:
    BLE* ble;
    ReadWriteGattCharacteristic<T>* state;
};

class SimpleBLE {
public:
    SimpleBLE(const char* aName, uint16_t aInterval = 1000) : name(aName), interval(aInterval) {
        ble = &BLE::Instance();
    }
    ~SimpleBLE() {}
    
    // Start up the BLE service and just run with it!
    void spin() {
        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 */ }
    
        while (true) {
            ble->waitForEvent();
        }
    }
    
    template <typename T>
    ReadOnlyCharacteristic<T>* createReadOnlyChar(uint16_t serviceUuid, 
                                                 uint16_t charUuid, 
                                                 bool enableNotify,
                                                 T defaultValue) {
        ReadOnlyCharacteristic<T>* c = new ReadOnlyCharacteristic<T>(ble, charUuid, enableNotify, defaultValue);
        
        if (services.count(serviceUuid) == 0) {
            services[serviceUuid] = new vector<GattCharacteristic*>();
        }
        
        services[serviceUuid]->push_back(c->getChar());
        
        return c;
    }

    template <typename T>
    ReadWriteCharacteristic<T>* createReadWriteChar(uint16_t serviceUuid, 
                                                 uint16_t charUuid, 
                                                 bool enableNotify,
                                                 T defaultValue,
                                                 void(*callback)(const uint8_t*, size_t)) {
        ReadWriteCharacteristic<T>* c = new ReadWriteCharacteristic<T>(ble, charUuid, enableNotify, defaultValue);

        if (services.count(serviceUuid) == 0) {
            services[serviceUuid] = new vector<GattCharacteristic*>();
        }
        
        services[serviceUuid]->push_back(c->getChar());
        writeCallbacks[c->getChar()] = (void*)callback;
        
        return c;
    }
    
    void onDisconnection(Gap::DisconnectionEventCallback_t callback) {
        ble->gap().onDisconnection(callback);
    }
    
    void onConnection(Gap::ConnectionEventCallback_t callback) {
        ble->gap().onConnection(callback);
    }
    
    void onDataWrittenCallback(const GattWriteCallbackParams *params) {
        // see if we know for which char this message is...
        typedef std::map<GattCharacteristic*, void* >::iterator it_type;
        for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) {
            if (it->first->getValueHandle() == params->handle) {
                void(*func)(const uint8_t*, size_t) = (void(*)(const uint8_t*, size_t))it->second;
                
                func(params->data, params->len);
            }
        }
        
        // handle corresponds to the characteristic being written
        // then we can read data to get a buffer of the actual data
//        if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) {
//            // When writing 1 -> turn LED on, 0 -> turn LED off
//            char val = params->data[0];
//            actuatedLED = val == 1 ? LED_ON : LED_OFF;
//        }
    }

    
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[services.size()];
        
        size_t counter = 0;
        typedef std::map<std::uint16_t, vector<GattCharacteristic*>* >::iterator it_type;
        for(it_type it = services.begin(); it != services.end(); it++) {
            printf("Creating service 0x%x\n", it->first);

            uuid16_list[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);
        }

        ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
        ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
        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\n");
    }

    BLE* ble;
    const char* name;
    uint16_t interval;
    map<uint16_t, vector<GattCharacteristic*>* > services;
    map<GattCharacteristic*, void*> writeCallbacks;
};