SimpleBLE prototype
Dependencies: BLE_API mbed nRF51822
SimpleBLE.h@1:acae50e4bc88, 2016-05-11 (annotated)
- Committer:
- janjongboom
- Date:
- Wed May 11 08:58:49 2016 +0000
- Revision:
- 1:acae50e4bc88
- Parent:
- 0:0c885d287f5a
LightSensor
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
janjongboom | 0:0c885d287f5a | 1 | /** |
janjongboom | 0:0c885d287f5a | 2 | * Because BLE_API is too hard |
janjongboom | 0:0c885d287f5a | 3 | */ |
janjongboom | 0:0c885d287f5a | 4 | #include <string> |
janjongboom | 0:0c885d287f5a | 5 | #include <vector> |
janjongboom | 0:0c885d287f5a | 6 | #include <map> |
janjongboom | 0:0c885d287f5a | 7 | #include "ble/BLE.h" |
janjongboom | 0:0c885d287f5a | 8 | |
janjongboom | 0:0c885d287f5a | 9 | using namespace std; |
janjongboom | 0:0c885d287f5a | 10 | |
janjongboom | 0:0c885d287f5a | 11 | template <class T> |
janjongboom | 0:0c885d287f5a | 12 | class ReadOnlyCharacteristic { |
janjongboom | 0:0c885d287f5a | 13 | public: |
janjongboom | 0:0c885d287f5a | 14 | ReadOnlyCharacteristic(BLE* aBle, const uint16_t aCharUuid, bool enableNotify, T defaultValue) : |
janjongboom | 0:0c885d287f5a | 15 | ble(aBle) |
janjongboom | 0:0c885d287f5a | 16 | { |
janjongboom | 0:0c885d287f5a | 17 | state = new ReadOnlyGattCharacteristic<T>(aCharUuid, new T(defaultValue), enableNotify ? |
janjongboom | 0:0c885d287f5a | 18 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : |
janjongboom | 0:0c885d287f5a | 19 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
janjongboom | 0:0c885d287f5a | 20 | } |
janjongboom | 0:0c885d287f5a | 21 | |
janjongboom | 0:0c885d287f5a | 22 | ~ReadOnlyCharacteristic() { |
janjongboom | 0:0c885d287f5a | 23 | // @todo clear defaultValue |
janjongboom | 0:0c885d287f5a | 24 | if (state) { |
janjongboom | 0:0c885d287f5a | 25 | free(state); |
janjongboom | 0:0c885d287f5a | 26 | } |
janjongboom | 0:0c885d287f5a | 27 | } |
janjongboom | 0:0c885d287f5a | 28 | |
janjongboom | 0:0c885d287f5a | 29 | void update(T newValue) { |
janjongboom | 0:0c885d287f5a | 30 | ble->gattServer().write(state->getValueHandle(), (uint8_t *)&newValue, sizeof(T)); |
janjongboom | 0:0c885d287f5a | 31 | } |
janjongboom | 0:0c885d287f5a | 32 | |
janjongboom | 0:0c885d287f5a | 33 | ReadOnlyGattCharacteristic<T>* getChar(void) { |
janjongboom | 0:0c885d287f5a | 34 | return state; |
janjongboom | 0:0c885d287f5a | 35 | } |
janjongboom | 0:0c885d287f5a | 36 | |
janjongboom | 0:0c885d287f5a | 37 | private: |
janjongboom | 0:0c885d287f5a | 38 | BLE* ble; |
janjongboom | 0:0c885d287f5a | 39 | ReadOnlyGattCharacteristic<T>* state; |
janjongboom | 0:0c885d287f5a | 40 | }; |
janjongboom | 0:0c885d287f5a | 41 | |
janjongboom | 0:0c885d287f5a | 42 | template <class T> |
janjongboom | 0:0c885d287f5a | 43 | class ReadWriteCharacteristic { |
janjongboom | 0:0c885d287f5a | 44 | public: |
janjongboom | 0:0c885d287f5a | 45 | ReadWriteCharacteristic(BLE* aBle, const uint16_t aCharUuid, bool enableNotify, T defaultValue) : |
janjongboom | 0:0c885d287f5a | 46 | ble(aBle) |
janjongboom | 0:0c885d287f5a | 47 | { |
janjongboom | 0:0c885d287f5a | 48 | state = new ReadWriteGattCharacteristic<T>(aCharUuid, new T(defaultValue), enableNotify ? |
janjongboom | 0:0c885d287f5a | 49 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY : |
janjongboom | 0:0c885d287f5a | 50 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
janjongboom | 0:0c885d287f5a | 51 | } |
janjongboom | 0:0c885d287f5a | 52 | |
janjongboom | 0:0c885d287f5a | 53 | ~ReadWriteCharacteristic() { |
janjongboom | 0:0c885d287f5a | 54 | // @todo clear defaultValue |
janjongboom | 0:0c885d287f5a | 55 | if (state) { |
janjongboom | 0:0c885d287f5a | 56 | free(state); |
janjongboom | 0:0c885d287f5a | 57 | } |
janjongboom | 0:0c885d287f5a | 58 | } |
janjongboom | 0:0c885d287f5a | 59 | |
janjongboom | 0:0c885d287f5a | 60 | void update(T newValue) { |
janjongboom | 0:0c885d287f5a | 61 | ble->gattServer().write(state->getValueHandle(), (uint8_t *)&newValue, sizeof(T)); |
janjongboom | 0:0c885d287f5a | 62 | } |
janjongboom | 0:0c885d287f5a | 63 | |
janjongboom | 0:0c885d287f5a | 64 | ReadWriteGattCharacteristic<T>* getChar(void) { |
janjongboom | 0:0c885d287f5a | 65 | return state; |
janjongboom | 0:0c885d287f5a | 66 | } |
janjongboom | 0:0c885d287f5a | 67 | |
janjongboom | 0:0c885d287f5a | 68 | private: |
janjongboom | 0:0c885d287f5a | 69 | BLE* ble; |
janjongboom | 0:0c885d287f5a | 70 | ReadWriteGattCharacteristic<T>* state; |
janjongboom | 0:0c885d287f5a | 71 | }; |
janjongboom | 0:0c885d287f5a | 72 | |
janjongboom | 0:0c885d287f5a | 73 | class SimpleBLE { |
janjongboom | 0:0c885d287f5a | 74 | public: |
janjongboom | 0:0c885d287f5a | 75 | SimpleBLE(const char* aName, uint16_t aInterval = 1000) : name(aName), interval(aInterval) { |
janjongboom | 0:0c885d287f5a | 76 | ble = &BLE::Instance(); |
janjongboom | 0:0c885d287f5a | 77 | } |
janjongboom | 0:0c885d287f5a | 78 | ~SimpleBLE() {} |
janjongboom | 0:0c885d287f5a | 79 | |
janjongboom | 0:0c885d287f5a | 80 | // Start up the BLE service and just run with it! |
janjongboom | 0:0c885d287f5a | 81 | void spin() { |
janjongboom | 0:0c885d287f5a | 82 | ble->init(this, &SimpleBLE::bleInitComplete); |
janjongboom | 0:0c885d287f5a | 83 | |
janjongboom | 0:0c885d287f5a | 84 | /* SpinWait for initialization to complete. This is necessary because the |
janjongboom | 0:0c885d287f5a | 85 | * BLE object is used in the main loop below. */ |
janjongboom | 0:0c885d287f5a | 86 | while (ble->hasInitialized() == false) { /* spin loop */ } |
janjongboom | 0:0c885d287f5a | 87 | |
janjongboom | 0:0c885d287f5a | 88 | while (true) { |
janjongboom | 0:0c885d287f5a | 89 | ble->waitForEvent(); |
janjongboom | 0:0c885d287f5a | 90 | } |
janjongboom | 0:0c885d287f5a | 91 | } |
janjongboom | 0:0c885d287f5a | 92 | |
janjongboom | 0:0c885d287f5a | 93 | template <typename T> |
janjongboom | 0:0c885d287f5a | 94 | ReadOnlyCharacteristic<T>* createReadOnlyChar(uint16_t serviceUuid, |
janjongboom | 0:0c885d287f5a | 95 | uint16_t charUuid, |
janjongboom | 0:0c885d287f5a | 96 | bool enableNotify, |
janjongboom | 0:0c885d287f5a | 97 | T defaultValue) { |
janjongboom | 0:0c885d287f5a | 98 | ReadOnlyCharacteristic<T>* c = new ReadOnlyCharacteristic<T>(ble, charUuid, enableNotify, defaultValue); |
janjongboom | 0:0c885d287f5a | 99 | |
janjongboom | 0:0c885d287f5a | 100 | if (services.count(serviceUuid) == 0) { |
janjongboom | 0:0c885d287f5a | 101 | services[serviceUuid] = new vector<GattCharacteristic*>(); |
janjongboom | 0:0c885d287f5a | 102 | } |
janjongboom | 0:0c885d287f5a | 103 | |
janjongboom | 0:0c885d287f5a | 104 | services[serviceUuid]->push_back(c->getChar()); |
janjongboom | 0:0c885d287f5a | 105 | |
janjongboom | 0:0c885d287f5a | 106 | return c; |
janjongboom | 0:0c885d287f5a | 107 | } |
janjongboom | 0:0c885d287f5a | 108 | |
janjongboom | 0:0c885d287f5a | 109 | template <typename T> |
janjongboom | 0:0c885d287f5a | 110 | ReadWriteCharacteristic<T>* createReadWriteChar(uint16_t serviceUuid, |
janjongboom | 0:0c885d287f5a | 111 | uint16_t charUuid, |
janjongboom | 0:0c885d287f5a | 112 | bool enableNotify, |
janjongboom | 0:0c885d287f5a | 113 | T defaultValue, |
janjongboom | 0:0c885d287f5a | 114 | void(*callback)(const uint8_t*, size_t)) { |
janjongboom | 0:0c885d287f5a | 115 | ReadWriteCharacteristic<T>* c = new ReadWriteCharacteristic<T>(ble, charUuid, enableNotify, defaultValue); |
janjongboom | 0:0c885d287f5a | 116 | |
janjongboom | 0:0c885d287f5a | 117 | if (services.count(serviceUuid) == 0) { |
janjongboom | 0:0c885d287f5a | 118 | services[serviceUuid] = new vector<GattCharacteristic*>(); |
janjongboom | 0:0c885d287f5a | 119 | } |
janjongboom | 0:0c885d287f5a | 120 | |
janjongboom | 0:0c885d287f5a | 121 | services[serviceUuid]->push_back(c->getChar()); |
janjongboom | 0:0c885d287f5a | 122 | writeCallbacks[c->getChar()] = (void*)callback; |
janjongboom | 0:0c885d287f5a | 123 | |
janjongboom | 0:0c885d287f5a | 124 | return c; |
janjongboom | 0:0c885d287f5a | 125 | } |
janjongboom | 0:0c885d287f5a | 126 | |
janjongboom | 0:0c885d287f5a | 127 | void onDisconnection(Gap::DisconnectionEventCallback_t callback) { |
janjongboom | 0:0c885d287f5a | 128 | ble->gap().onDisconnection(callback); |
janjongboom | 0:0c885d287f5a | 129 | } |
janjongboom | 0:0c885d287f5a | 130 | |
janjongboom | 0:0c885d287f5a | 131 | void onConnection(Gap::ConnectionEventCallback_t callback) { |
janjongboom | 0:0c885d287f5a | 132 | ble->gap().onConnection(callback); |
janjongboom | 0:0c885d287f5a | 133 | } |
janjongboom | 0:0c885d287f5a | 134 | |
janjongboom | 0:0c885d287f5a | 135 | void onDataWrittenCallback(const GattWriteCallbackParams *params) { |
janjongboom | 0:0c885d287f5a | 136 | // see if we know for which char this message is... |
janjongboom | 0:0c885d287f5a | 137 | typedef std::map<GattCharacteristic*, void* >::iterator it_type; |
janjongboom | 0:0c885d287f5a | 138 | for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) { |
janjongboom | 0:0c885d287f5a | 139 | if (it->first->getValueHandle() == params->handle) { |
janjongboom | 0:0c885d287f5a | 140 | void(*func)(const uint8_t*, size_t) = (void(*)(const uint8_t*, size_t))it->second; |
janjongboom | 0:0c885d287f5a | 141 | |
janjongboom | 0:0c885d287f5a | 142 | func(params->data, params->len); |
janjongboom | 0:0c885d287f5a | 143 | } |
janjongboom | 0:0c885d287f5a | 144 | } |
janjongboom | 0:0c885d287f5a | 145 | |
janjongboom | 0:0c885d287f5a | 146 | // handle corresponds to the characteristic being written |
janjongboom | 0:0c885d287f5a | 147 | // then we can read data to get a buffer of the actual data |
janjongboom | 0:0c885d287f5a | 148 | // if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) { |
janjongboom | 0:0c885d287f5a | 149 | // // When writing 1 -> turn LED on, 0 -> turn LED off |
janjongboom | 0:0c885d287f5a | 150 | // char val = params->data[0]; |
janjongboom | 0:0c885d287f5a | 151 | // actuatedLED = val == 1 ? LED_ON : LED_OFF; |
janjongboom | 0:0c885d287f5a | 152 | // } |
janjongboom | 0:0c885d287f5a | 153 | } |
janjongboom | 0:0c885d287f5a | 154 | |
janjongboom | 0:0c885d287f5a | 155 | |
janjongboom | 0:0c885d287f5a | 156 | private: |
janjongboom | 0:0c885d287f5a | 157 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) |
janjongboom | 0:0c885d287f5a | 158 | { |
janjongboom | 0:0c885d287f5a | 159 | printf("bleInitComplete\r\n"); |
janjongboom | 0:0c885d287f5a | 160 | |
janjongboom | 0:0c885d287f5a | 161 | BLE& ble = params->ble; |
janjongboom | 0:0c885d287f5a | 162 | ble_error_t error = params->error; |
janjongboom | 0:0c885d287f5a | 163 | |
janjongboom | 0:0c885d287f5a | 164 | if (error != BLE_ERROR_NONE) { |
janjongboom | 0:0c885d287f5a | 165 | printf("BLE Init error %d\r\n", error); |
janjongboom | 0:0c885d287f5a | 166 | return; |
janjongboom | 0:0c885d287f5a | 167 | } |
janjongboom | 0:0c885d287f5a | 168 | |
janjongboom | 0:0c885d287f5a | 169 | /* Ensure that it is the default instance of BLE */ |
janjongboom | 0:0c885d287f5a | 170 | if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { |
janjongboom | 0:0c885d287f5a | 171 | return; |
janjongboom | 0:0c885d287f5a | 172 | } |
janjongboom | 0:0c885d287f5a | 173 | |
janjongboom | 0:0c885d287f5a | 174 | ble.gattServer().onDataWritten(this, &SimpleBLE::onDataWrittenCallback); |
janjongboom | 0:0c885d287f5a | 175 | |
janjongboom | 0:0c885d287f5a | 176 | // let's add some services yo (why is there no 'auto' in mbed?) |
janjongboom | 0:0c885d287f5a | 177 | uint16_t uuid16_list[services.size()]; |
janjongboom | 0:0c885d287f5a | 178 | |
janjongboom | 0:0c885d287f5a | 179 | size_t counter = 0; |
janjongboom | 0:0c885d287f5a | 180 | typedef std::map<std::uint16_t, vector<GattCharacteristic*>* >::iterator it_type; |
janjongboom | 0:0c885d287f5a | 181 | for(it_type it = services.begin(); it != services.end(); it++) { |
janjongboom | 0:0c885d287f5a | 182 | printf("Creating service 0x%x\n", it->first); |
janjongboom | 0:0c885d287f5a | 183 | |
janjongboom | 0:0c885d287f5a | 184 | uuid16_list[counter++] = it->first; |
janjongboom | 0:0c885d287f5a | 185 | |
janjongboom | 0:0c885d287f5a | 186 | GattCharacteristic* charTable[it->second->size()]; |
janjongboom | 0:0c885d287f5a | 187 | for (size_t git = 0; git < it->second->size(); git++) { |
janjongboom | 0:0c885d287f5a | 188 | charTable[git] = it->second->at(git); |
janjongboom | 0:0c885d287f5a | 189 | } |
janjongboom | 0:0c885d287f5a | 190 | GattService service(it->first, charTable, it->second->size()); |
janjongboom | 0:0c885d287f5a | 191 | ble.gattServer().addService(service); |
janjongboom | 0:0c885d287f5a | 192 | } |
janjongboom | 0:0c885d287f5a | 193 | |
janjongboom | 0:0c885d287f5a | 194 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
janjongboom | 0:0c885d287f5a | 195 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
janjongboom | 0:0c885d287f5a | 196 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)name, strlen(name)); |
janjongboom | 0:0c885d287f5a | 197 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
janjongboom | 0:0c885d287f5a | 198 | ble.gap().setAdvertisingInterval(interval); |
janjongboom | 0:0c885d287f5a | 199 | ble.gap().startAdvertising(); |
janjongboom | 0:0c885d287f5a | 200 | |
janjongboom | 0:0c885d287f5a | 201 | printf("Started advertising\n"); |
janjongboom | 0:0c885d287f5a | 202 | } |
janjongboom | 0:0c885d287f5a | 203 | |
janjongboom | 0:0c885d287f5a | 204 | BLE* ble; |
janjongboom | 0:0c885d287f5a | 205 | const char* name; |
janjongboom | 0:0c885d287f5a | 206 | uint16_t interval; |
janjongboom | 0:0c885d287f5a | 207 | map<uint16_t, vector<GattCharacteristic*>* > services; |
janjongboom | 0:0c885d287f5a | 208 | map<GattCharacteristic*, void*> writeCallbacks; |
janjongboom | 0:0c885d287f5a | 209 | }; |
janjongboom | 0:0c885d287f5a | 210 |