Library that exposes BLE characteristics as ordinary variables.

Dependents:   SimpleBLE-Example-mbed-os-5 SimpleBLE-Example ObCP_ENSMM_Test SimpleBLE-ObCP_ENSMM_V2019_Test_BLE

Looking for example code? See SimpleBLE-Example.

Looking for the blog post about this library? See A new Bluetooth library: SimpleBLE.

SimpleBLE is a library which allows you to easily add Bluetooth Low Energy support to any application, without having to change the way you write code. It's goal is to expose any value or sensor over BLE in a single line of code. Let's say you're reading a sensor value every second from pin A0:

uint16_t lightValue;

AnalogIn light(A0);
void read() {
  lightValue = light.read_u16();
  printf("Value is now %d\n", lightValue);
}

Ticker t;
t.attach(&read, 1.0f);

Now we can expose this sensor to any BLE client using SimpleBLE:

SimpleChar<uint16_t> lightValue = ble.readOnly_u16(0x8000, 0x8001);

AnalogIn light(A0);
void read() {
  lightValue = light.read_u16();
  printf("Value is now %d\n", lightValue);
}

Ticker t;
t.attach(&read, 1.0f);

SimpleBLE will automatically gather services for you, bootstrap the BLE runtime, react to write callbacks and update the underlying BLE characteristic whenever the variable gets changed.

Setting up the library

First import this library to the application where you want to use it. Then load SimpleBLE like this:

#include "mbed.h"
#include "SimpleBLE.h"

SimpleBLE ble("DEVICE_NAME"); // second argument is the advertisement interval (default: 1000 ms.)

// variables here!

int main(int, char**) {
    ble.start();
    while (1) {
        ble.waitForEvent();
    }
}

You'll also need to import the BLE library for your platform (e.g. nrf51822 for nRF51-DK and micro:bit). If you grab the example program, all should be set.

After you build and flash this application the device will now show up as 'DEVICE_NAME' in any BLE scanner like nRF Master Control Panel.

Reading and writing values

Every variable that you declare after creating the `SimpleBLE` object, and calling `start()` will automatically be exposed over BLE. We have three different types of objects:

  • readOnly - Variable can only be read over BLE.
  • readWrite - Variable can be read and written over BLE.
  • writeOnly - Variable can be written over BLE, but not read.

Creating a new variable is done by calling the respective function on the simpleBLE object, postfixed by the type you want the variable to have:

SimpleBLE ble("DEVICE_NAME");

SimpleChar<uint8_t> myVar = ble.readOnly_u8(0x8200, 0x8201); // creates uint8_t

The postfix has to be either: u8 (uint8_t), u16 (uint16_t), u32 (uint32_t), i8 (int8_t), i16 (int16_t), i32 (int32_t), bool (bool) or float (float).

The functions take four (non-write) or five (write) arguments:

  • serviceUUID - Which service should this variable fall under. Either use a uint16_t (shorthand) or you can use a string (full UUID).
  • characterUUID - Which character this variable should have. Also, use uint16_t or a string.
  • observable - Whether a BLE client can subscribe to updates on this characteristic (default: true).
  • defaultValue - Default value of the characteristic (default: 0 or 0.0f, depending on your type).
  • callback - Function to be called whenever the value of your characteristic was updated over BLE (only available for variables that support writing).

For example, this is how we make a non-observable readWrite characteristic, with a default value of 100, and a callback function:

SimpleBLE ble("DEVICE_NAME");

void updated(uint32_t newValue) {
  printf("My value was updated, and is now %d\n", newValue);
}

SimpleChar<uint32_t> myVar = ble.readWrite_u32(0x9341, 0x9342, false, 100, &updated);

Just like normal variables

SimpleBLE variables behave just like normal variables, you can read and write straight from them. For example, this will compile just fine:

SimpleChar<uint8_t> heartrate = ble.readOnly_u8(0x180d, 0x2a37, true, 100);

void updateHr() {
  heartrate = heartrate + 1;
  if (heartrate > 180) {
    heartrate = 100;
  }
}

Ticker t;
t.attach(updateHr, 1.0f);

What to use it for?

I wrote this library because I do quite a lot of workshops and hackathons, and I have seen that BLE_API is too complicated for people who do not do embedded development or C++ on a daily basis. Exposing a new sensor over Bluetooth should be a single line of code. So if you're running any workshops, give this lib a go and let me know your experiences.

Committer:
janjongboom
Date:
Tue May 17 19:33:34 2016 +0000
Revision:
1:17c8f5afa7bc
Parent:
0:2ecd71f6ab04
Child:
2:15329a3de04c
Switch from generics to macros so we can whitelist only primitives

Who changed what in which revision?

UserRevisionLine numberNew contents of line
janjongboom 1:17c8f5afa7bc 1 /*
janjongboom 1:17c8f5afa7bc 2 * Copyright (c) 2015 ARM Limited. All rights reserved.
janjongboom 1:17c8f5afa7bc 3 * SPDX-License-Identifier: Apache-2.0
janjongboom 1:17c8f5afa7bc 4 * Licensed under the Apache License, Version 2.0 (the License); you may
janjongboom 1:17c8f5afa7bc 5 * not use this file except in compliance with the License.
janjongboom 1:17c8f5afa7bc 6 * You may obtain a copy of the License at
janjongboom 1:17c8f5afa7bc 7 *
janjongboom 1:17c8f5afa7bc 8 * http://www.apache.org/licenses/LICENSE-2.0
janjongboom 1:17c8f5afa7bc 9 *
janjongboom 1:17c8f5afa7bc 10 * Unless required by applicable law or agreed to in writing, software
janjongboom 1:17c8f5afa7bc 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
janjongboom 1:17c8f5afa7bc 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
janjongboom 1:17c8f5afa7bc 13 * See the License for the specific language governing permissions and
janjongboom 1:17c8f5afa7bc 14 * limitations under the License.
janjongboom 0:2ecd71f6ab04 15 */
janjongboom 1:17c8f5afa7bc 16
janjongboom 0:2ecd71f6ab04 17 #include <string>
janjongboom 0:2ecd71f6ab04 18 #include <sstream>
janjongboom 0:2ecd71f6ab04 19 #include <vector>
janjongboom 0:2ecd71f6ab04 20 #include <map>
janjongboom 0:2ecd71f6ab04 21 #include "ble/BLE.h"
janjongboom 0:2ecd71f6ab04 22
janjongboom 1:17c8f5afa7bc 23 #define def_fn(T, postfix) \
janjongboom 1:17c8f5afa7bc 24 SimpleChar<T> readOnly_##postfix \
janjongboom 1:17c8f5afa7bc 25 (uint16_t serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T()) { \
janjongboom 1:17c8f5afa7bc 26 return readOnly<T>(serviceUuid, charUuid, enableNotify, defaultValue); \
janjongboom 1:17c8f5afa7bc 27 }\
janjongboom 1:17c8f5afa7bc 28 SimpleChar<T> readOnly_##postfix \
janjongboom 1:17c8f5afa7bc 29 (const char* serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T()) { \
janjongboom 1:17c8f5afa7bc 30 return readOnly<T>(serviceUuid, charUuid, enableNotify, defaultValue); \
janjongboom 1:17c8f5afa7bc 31 }\
janjongboom 1:17c8f5afa7bc 32 \
janjongboom 1:17c8f5afa7bc 33 SimpleChar<T> readWrite_##postfix \
janjongboom 1:17c8f5afa7bc 34 (uint16_t serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T(), void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 35 return readWrite<T>(serviceUuid, charUuid, enableNotify, defaultValue, callback); \
janjongboom 1:17c8f5afa7bc 36 }\
janjongboom 1:17c8f5afa7bc 37 SimpleChar<T> readWrite_##postfix \
janjongboom 1:17c8f5afa7bc 38 (const char* serviceUuid, const UUID& charUuid, bool enableNotify = true, T defaultValue = T(), void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 39 return readWrite<T>(serviceUuid, charUuid, enableNotify, defaultValue, callback); \
janjongboom 1:17c8f5afa7bc 40 }\
janjongboom 1:17c8f5afa7bc 41 SimpleChar<T> readWrite_##postfix \
janjongboom 1:17c8f5afa7bc 42 (uint16_t serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 43 return readWrite<T>(serviceUuid, charUuid, callback); \
janjongboom 1:17c8f5afa7bc 44 }\
janjongboom 1:17c8f5afa7bc 45 SimpleChar<T> readWrite_##postfix \
janjongboom 1:17c8f5afa7bc 46 (const char* serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 47 return readWrite<T>(serviceUuid, charUuid, callback); \
janjongboom 1:17c8f5afa7bc 48 }\
janjongboom 1:17c8f5afa7bc 49 \
janjongboom 1:17c8f5afa7bc 50 SimpleChar<T> writeOnly_##postfix \
janjongboom 1:17c8f5afa7bc 51 (uint16_t serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 52 return writeOnly<T>(serviceUuid, charUuid, callback); \
janjongboom 1:17c8f5afa7bc 53 }\
janjongboom 1:17c8f5afa7bc 54 SimpleChar<T> writeOnly_##postfix \
janjongboom 1:17c8f5afa7bc 55 (const char* serviceUuid, const UUID& charUuid, void(*callback)(T) = NULL) { \
janjongboom 1:17c8f5afa7bc 56 return writeOnly<T>(serviceUuid, charUuid, callback); \
janjongboom 1:17c8f5afa7bc 57 }
janjongboom 1:17c8f5afa7bc 58
janjongboom 0:2ecd71f6ab04 59 using namespace std;
janjongboom 0:2ecd71f6ab04 60
janjongboom 0:2ecd71f6ab04 61 /**
janjongboom 0:2ecd71f6ab04 62 * Class so we can call onDataWritten on any SimpleCharInternal regardless of <T,U>
janjongboom 0:2ecd71f6ab04 63 */
janjongboom 0:2ecd71f6ab04 64 class Updatable {
janjongboom 0:2ecd71f6ab04 65 public:
janjongboom 0:2ecd71f6ab04 66 virtual void onDataWritten(const uint8_t* data, size_t len) = 0;
janjongboom 0:2ecd71f6ab04 67 };
janjongboom 0:2ecd71f6ab04 68
janjongboom 0:2ecd71f6ab04 69 /**
janjongboom 0:2ecd71f6ab04 70 * Class that we wrap in SimpleChar so we can just implement operators,
janjongboom 0:2ecd71f6ab04 71 * without having to type the full type of U when using this code.
janjongboom 0:2ecd71f6ab04 72 * Whenever we get 'auto' we can get rid of this.
janjongboom 0:2ecd71f6ab04 73 */
janjongboom 0:2ecd71f6ab04 74 template <class T>
janjongboom 0:2ecd71f6ab04 75 class SimpleCharBase {
janjongboom 0:2ecd71f6ab04 76 public:
janjongboom 0:2ecd71f6ab04 77 virtual void update(T newValue) = 0;
janjongboom 0:2ecd71f6ab04 78 virtual T* getValue(void) = 0;
janjongboom 0:2ecd71f6ab04 79 };
janjongboom 0:2ecd71f6ab04 80
janjongboom 0:2ecd71f6ab04 81 /**
janjongboom 0:2ecd71f6ab04 82 * Actual implementation of the char
janjongboom 0:2ecd71f6ab04 83 * T is the underlying type, U is the GattCharacteristic it's wrapping
janjongboom 0:2ecd71f6ab04 84 */
janjongboom 0:2ecd71f6ab04 85 template <class T, template <typename T2> class U>
janjongboom 0:2ecd71f6ab04 86 class SimpleCharInternal : public Updatable, public SimpleCharBase<T> {
janjongboom 0:2ecd71f6ab04 87 public:
janjongboom 0:2ecd71f6ab04 88 SimpleCharInternal(BLE* aBle,
janjongboom 0:2ecd71f6ab04 89 const UUID &uuid,
janjongboom 0:2ecd71f6ab04 90 GattCharacteristic::Properties_t aGattChar,
janjongboom 0:2ecd71f6ab04 91 T aDefaultValue,
janjongboom 0:2ecd71f6ab04 92 void(*aCallback)(T) = NULL) :
janjongboom 0:2ecd71f6ab04 93 ble(aBle), value(new T(aDefaultValue)), callback(aCallback)
janjongboom 0:2ecd71f6ab04 94 {
janjongboom 0:2ecd71f6ab04 95 state = new U<T>(uuid, value, aGattChar);
janjongboom 0:2ecd71f6ab04 96 }
janjongboom 0:2ecd71f6ab04 97
janjongboom 0:2ecd71f6ab04 98 ~SimpleCharInternal() {
janjongboom 0:2ecd71f6ab04 99 if (state) {
janjongboom 0:2ecd71f6ab04 100 free(state);
janjongboom 0:2ecd71f6ab04 101 }
janjongboom 0:2ecd71f6ab04 102 if (value) {
janjongboom 0:2ecd71f6ab04 103 free(value);
janjongboom 0:2ecd71f6ab04 104 }
janjongboom 0:2ecd71f6ab04 105 }
janjongboom 0:2ecd71f6ab04 106
janjongboom 0:2ecd71f6ab04 107 virtual void update(T newValue) {
janjongboom 0:2ecd71f6ab04 108 *value = newValue;
janjongboom 0:2ecd71f6ab04 109 ble->gattServer().write(state->getValueHandle(), (uint8_t *)value, sizeof(T));
janjongboom 0:2ecd71f6ab04 110 }
janjongboom 0:2ecd71f6ab04 111
janjongboom 0:2ecd71f6ab04 112 U<T>* getChar(void) {
janjongboom 0:2ecd71f6ab04 113 return state;
janjongboom 0:2ecd71f6ab04 114 }
janjongboom 0:2ecd71f6ab04 115
janjongboom 0:2ecd71f6ab04 116 virtual T* getValue(void) {
janjongboom 0:2ecd71f6ab04 117 return value;
janjongboom 0:2ecd71f6ab04 118 }
janjongboom 0:2ecd71f6ab04 119
janjongboom 0:2ecd71f6ab04 120 virtual void onDataWritten(const uint8_t* data, size_t len) {
janjongboom 0:2ecd71f6ab04 121 *value = ((T*)data)[0];
janjongboom 0:2ecd71f6ab04 122 if (callback) {
janjongboom 0:2ecd71f6ab04 123 callback(*value);
janjongboom 0:2ecd71f6ab04 124 }
janjongboom 0:2ecd71f6ab04 125 }
janjongboom 0:2ecd71f6ab04 126
janjongboom 0:2ecd71f6ab04 127 private:
janjongboom 0:2ecd71f6ab04 128 BLE* ble;
janjongboom 0:2ecd71f6ab04 129 T* value;
janjongboom 0:2ecd71f6ab04 130 U<T>* state;
janjongboom 0:2ecd71f6ab04 131 void(*callback)(T);
janjongboom 0:2ecd71f6ab04 132 };
janjongboom 0:2ecd71f6ab04 133
janjongboom 0:2ecd71f6ab04 134 /**
janjongboom 0:2ecd71f6ab04 135 * This is what the user gets back. it's nice and short so don't have to type much.
janjongboom 0:2ecd71f6ab04 136 * If we get 'auto' we can get rid of this.
janjongboom 0:2ecd71f6ab04 137 */
janjongboom 0:2ecd71f6ab04 138 template <class T>
janjongboom 0:2ecd71f6ab04 139 class SimpleChar {
janjongboom 0:2ecd71f6ab04 140 public:
janjongboom 0:2ecd71f6ab04 141 SimpleChar(SimpleCharBase<T>* aBase) : base(aBase) {
janjongboom 0:2ecd71f6ab04 142 }
janjongboom 0:2ecd71f6ab04 143 ~SimpleChar() {
janjongboom 0:2ecd71f6ab04 144 if (base) {
janjongboom 0:2ecd71f6ab04 145 delete base;
janjongboom 0:2ecd71f6ab04 146 }
janjongboom 0:2ecd71f6ab04 147 }
janjongboom 0:2ecd71f6ab04 148
janjongboom 0:2ecd71f6ab04 149 T operator=(const T& newValue) {
janjongboom 0:2ecd71f6ab04 150 base->update(newValue);
janjongboom 0:2ecd71f6ab04 151 return newValue;
janjongboom 0:2ecd71f6ab04 152 };
janjongboom 0:2ecd71f6ab04 153 operator T() const {
janjongboom 0:2ecd71f6ab04 154 return *(base->getValue());
janjongboom 0:2ecd71f6ab04 155 };
janjongboom 0:2ecd71f6ab04 156
janjongboom 0:2ecd71f6ab04 157 private:
janjongboom 0:2ecd71f6ab04 158 SimpleCharBase<T>* base;
janjongboom 0:2ecd71f6ab04 159 };
janjongboom 0:2ecd71f6ab04 160
janjongboom 0:2ecd71f6ab04 161
janjongboom 0:2ecd71f6ab04 162 class SimpleBLE {
janjongboom 0:2ecd71f6ab04 163 public:
janjongboom 1:17c8f5afa7bc 164 SimpleBLE(const char* aName, uint16_t aInterval = 1000, bool aLogging = true)
janjongboom 1:17c8f5afa7bc 165 : name(aName), interval(aInterval), logging(aLogging)
janjongboom 1:17c8f5afa7bc 166 {
janjongboom 0:2ecd71f6ab04 167 ble = &BLE::Instance();
janjongboom 0:2ecd71f6ab04 168 }
janjongboom 0:2ecd71f6ab04 169 ~SimpleBLE() {}
janjongboom 0:2ecd71f6ab04 170
janjongboom 0:2ecd71f6ab04 171 void start() {
janjongboom 0:2ecd71f6ab04 172 ble->init(this, &SimpleBLE::bleInitComplete);
janjongboom 0:2ecd71f6ab04 173
janjongboom 0:2ecd71f6ab04 174 /* SpinWait for initialization to complete. This is necessary because the
janjongboom 0:2ecd71f6ab04 175 * BLE object is used in the main loop below. */
janjongboom 0:2ecd71f6ab04 176 while (ble->hasInitialized() == false) { /* spin loop */ }
janjongboom 0:2ecd71f6ab04 177 }
janjongboom 0:2ecd71f6ab04 178
janjongboom 0:2ecd71f6ab04 179 // Start up the BLE service and just run with it!
janjongboom 0:2ecd71f6ab04 180 void waitForEvent() {
janjongboom 0:2ecd71f6ab04 181 ble->waitForEvent();
janjongboom 1:17c8f5afa7bc 182 }
janjongboom 1:17c8f5afa7bc 183
janjongboom 1:17c8f5afa7bc 184 void onDisconnection(Gap::DisconnectionEventCallback_t callback) {
janjongboom 1:17c8f5afa7bc 185 ble->gap().onDisconnection(callback);
janjongboom 1:17c8f5afa7bc 186 }
janjongboom 1:17c8f5afa7bc 187
janjongboom 1:17c8f5afa7bc 188 void onConnection(Gap::ConnectionEventCallback_t callback) {
janjongboom 1:17c8f5afa7bc 189 ble->gap().onConnection(callback);
janjongboom 1:17c8f5afa7bc 190 }
janjongboom 1:17c8f5afa7bc 191
janjongboom 1:17c8f5afa7bc 192 BLE* getBle(void) {
janjongboom 1:17c8f5afa7bc 193 return ble;
janjongboom 1:17c8f5afa7bc 194 }
janjongboom 1:17c8f5afa7bc 195
janjongboom 1:17c8f5afa7bc 196 def_fn(uint8_t, u8)
janjongboom 1:17c8f5afa7bc 197 def_fn(uint16_t, u16)
janjongboom 1:17c8f5afa7bc 198 def_fn(uint32_t, u32)
janjongboom 1:17c8f5afa7bc 199 def_fn(int8_t, i8)
janjongboom 1:17c8f5afa7bc 200 def_fn(int16_t, i16)
janjongboom 1:17c8f5afa7bc 201 def_fn(int32_t, i32)
janjongboom 1:17c8f5afa7bc 202 def_fn(bool, bool)
janjongboom 1:17c8f5afa7bc 203
janjongboom 1:17c8f5afa7bc 204 private:
janjongboom 1:17c8f5afa7bc 205 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
janjongboom 1:17c8f5afa7bc 206 {
janjongboom 1:17c8f5afa7bc 207 if (logging) printf("bleInitComplete\r\n");
janjongboom 1:17c8f5afa7bc 208
janjongboom 1:17c8f5afa7bc 209 BLE& ble = params->ble;
janjongboom 1:17c8f5afa7bc 210 ble_error_t error = params->error;
janjongboom 1:17c8f5afa7bc 211
janjongboom 1:17c8f5afa7bc 212 if (error != BLE_ERROR_NONE) {
janjongboom 1:17c8f5afa7bc 213 if (logging) printf("BLE Init error %d\r\n", error);
janjongboom 1:17c8f5afa7bc 214 return;
janjongboom 1:17c8f5afa7bc 215 }
janjongboom 1:17c8f5afa7bc 216
janjongboom 1:17c8f5afa7bc 217 /* Ensure that it is the default instance of BLE */
janjongboom 1:17c8f5afa7bc 218 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
janjongboom 1:17c8f5afa7bc 219 return;
janjongboom 1:17c8f5afa7bc 220 }
janjongboom 1:17c8f5afa7bc 221
janjongboom 1:17c8f5afa7bc 222 ble.gattServer().onDataWritten(this, &SimpleBLE::onDataWrittenCallback);
janjongboom 1:17c8f5afa7bc 223
janjongboom 1:17c8f5afa7bc 224 // let's add some services yo (why is there no 'auto' in mbed?)
janjongboom 1:17c8f5afa7bc 225 uint16_t uuid16_list[uint16_services.size()];
janjongboom 1:17c8f5afa7bc 226 size_t uuid16_counter = 0;
janjongboom 1:17c8f5afa7bc 227 {
janjongboom 1:17c8f5afa7bc 228 typedef std::map<uint16_t, vector<GattCharacteristic*>* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 229 for(it_type it = uint16_services.begin(); it != uint16_services.end(); it++) {
janjongboom 1:17c8f5afa7bc 230 if (logging) printf("Creating service 0x%x\n", it->first);
janjongboom 1:17c8f5afa7bc 231 uuid16_list[uuid16_counter++] = it->first;
janjongboom 1:17c8f5afa7bc 232
janjongboom 1:17c8f5afa7bc 233 GattCharacteristic* charTable[it->second->size()];
janjongboom 1:17c8f5afa7bc 234 for (size_t git = 0; git < it->second->size(); git++) {
janjongboom 1:17c8f5afa7bc 235 charTable[git] = it->second->at(git);
janjongboom 1:17c8f5afa7bc 236 }
janjongboom 1:17c8f5afa7bc 237
janjongboom 1:17c8f5afa7bc 238 GattService service(it->first, charTable, it->second->size());
janjongboom 1:17c8f5afa7bc 239 ble.gattServer().addService(service);
janjongboom 1:17c8f5afa7bc 240 }
janjongboom 1:17c8f5afa7bc 241 }
janjongboom 1:17c8f5afa7bc 242
janjongboom 1:17c8f5afa7bc 243 // 128 Bit services
janjongboom 1:17c8f5afa7bc 244 const char* uuid128_list[uint128_services.size()];
janjongboom 1:17c8f5afa7bc 245 size_t uuid128_counter = 0;
janjongboom 1:17c8f5afa7bc 246 {
janjongboom 1:17c8f5afa7bc 247 typedef std::map<string, vector<GattCharacteristic*>* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 248 for(it_type it = uint128_services.begin(); it != uint128_services.end(); it++) {
janjongboom 1:17c8f5afa7bc 249 if (logging) printf("Creating service %s\n", it->first.c_str());
janjongboom 1:17c8f5afa7bc 250 uuid128_list[uuid128_counter++] = it->first.c_str();
janjongboom 1:17c8f5afa7bc 251
janjongboom 1:17c8f5afa7bc 252 GattCharacteristic* charTable[it->second->size()];
janjongboom 1:17c8f5afa7bc 253 for (size_t git = 0; git < it->second->size(); git++) {
janjongboom 1:17c8f5afa7bc 254 charTable[git] = it->second->at(git);
janjongboom 1:17c8f5afa7bc 255 }
janjongboom 1:17c8f5afa7bc 256
janjongboom 1:17c8f5afa7bc 257 GattService service(UUID(it->first.c_str()), charTable, it->second->size());
janjongboom 1:17c8f5afa7bc 258 ble.gattServer().addService(service);
janjongboom 1:17c8f5afa7bc 259 }
janjongboom 1:17c8f5afa7bc 260 }
janjongboom 1:17c8f5afa7bc 261
janjongboom 1:17c8f5afa7bc 262 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
janjongboom 1:17c8f5afa7bc 263 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, uuid16_counter);
janjongboom 1:17c8f5afa7bc 264 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid128_list, uuid128_counter);
janjongboom 1:17c8f5afa7bc 265 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)name, strlen(name));
janjongboom 1:17c8f5afa7bc 266 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
janjongboom 1:17c8f5afa7bc 267 ble.gap().setAdvertisingInterval(interval);
janjongboom 1:17c8f5afa7bc 268 ble.gap().startAdvertising();
janjongboom 1:17c8f5afa7bc 269
janjongboom 1:17c8f5afa7bc 270 if (logging) printf("Started advertising\r\n");
janjongboom 1:17c8f5afa7bc 271 }
janjongboom 1:17c8f5afa7bc 272
janjongboom 1:17c8f5afa7bc 273 void onDataWrittenCallback(const GattWriteCallbackParams *params) {
janjongboom 1:17c8f5afa7bc 274 // see if we know for which char this message is...
janjongboom 1:17c8f5afa7bc 275 typedef std::map<GattCharacteristic*, Updatable* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 276 for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) {
janjongboom 1:17c8f5afa7bc 277 if (it->first->getValueHandle() == params->handle) {
janjongboom 1:17c8f5afa7bc 278 it->second->onDataWritten(params->data, params->len);
janjongboom 1:17c8f5afa7bc 279 }
janjongboom 1:17c8f5afa7bc 280 }
janjongboom 1:17c8f5afa7bc 281 }
janjongboom 1:17c8f5afa7bc 282
janjongboom 1:17c8f5afa7bc 283 void addToServices(uint16_t uuid, GattCharacteristic* c) {
janjongboom 1:17c8f5afa7bc 284 if (uint16_services.count(uuid) == 0) {
janjongboom 1:17c8f5afa7bc 285 uint16_services[uuid] = new vector<GattCharacteristic*>();
janjongboom 1:17c8f5afa7bc 286 }
janjongboom 1:17c8f5afa7bc 287
janjongboom 1:17c8f5afa7bc 288 uint16_services[uuid]->push_back(c);
janjongboom 1:17c8f5afa7bc 289 }
janjongboom 1:17c8f5afa7bc 290
janjongboom 1:17c8f5afa7bc 291 void addToServices(const char* aUuid, GattCharacteristic* c) {
janjongboom 1:17c8f5afa7bc 292 string uuid(aUuid);
janjongboom 1:17c8f5afa7bc 293 if (uint128_services.count(uuid) == 0) {
janjongboom 1:17c8f5afa7bc 294 uint128_services[uuid] = new vector<GattCharacteristic*>();
janjongboom 1:17c8f5afa7bc 295 }
janjongboom 1:17c8f5afa7bc 296
janjongboom 1:17c8f5afa7bc 297 uint128_services[uuid]->push_back(c);
janjongboom 0:2ecd71f6ab04 298 }
janjongboom 0:2ecd71f6ab04 299
janjongboom 0:2ecd71f6ab04 300 // === START READONLY ===
janjongboom 0:2ecd71f6ab04 301
janjongboom 0:2ecd71f6ab04 302 template <typename T>
janjongboom 0:2ecd71f6ab04 303 SimpleChar<T> readOnly(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 304 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 305 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 306 T defaultValue = T()) {
janjongboom 0:2ecd71f6ab04 307 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 308 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 309 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 310
janjongboom 0:2ecd71f6ab04 311 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 312 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue);
janjongboom 0:2ecd71f6ab04 313
janjongboom 0:2ecd71f6ab04 314 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 315
janjongboom 0:2ecd71f6ab04 316 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 317 }
janjongboom 0:2ecd71f6ab04 318
janjongboom 0:2ecd71f6ab04 319 template <typename T>
janjongboom 0:2ecd71f6ab04 320 SimpleChar<T> readOnly(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 321 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 322 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 323 T defaultValue = T()) {
janjongboom 0:2ecd71f6ab04 324 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 325 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 326 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 327
janjongboom 0:2ecd71f6ab04 328 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 329 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue);
janjongboom 0:2ecd71f6ab04 330
janjongboom 0:2ecd71f6ab04 331 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 332
janjongboom 0:2ecd71f6ab04 333 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 334 }
janjongboom 0:2ecd71f6ab04 335
janjongboom 0:2ecd71f6ab04 336 // === END READONLY ===
janjongboom 0:2ecd71f6ab04 337
janjongboom 0:2ecd71f6ab04 338 // === START READWRITE ===
janjongboom 0:2ecd71f6ab04 339
janjongboom 0:2ecd71f6ab04 340 template <typename T>
janjongboom 0:2ecd71f6ab04 341 SimpleChar<T> readWrite(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 342 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 343 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 344 T defaultValue = T(),
janjongboom 0:2ecd71f6ab04 345 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 346 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 347 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 348 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 349
janjongboom 0:2ecd71f6ab04 350 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 351 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback);
janjongboom 0:2ecd71f6ab04 352
janjongboom 0:2ecd71f6ab04 353 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 354
janjongboom 0:2ecd71f6ab04 355 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 356
janjongboom 0:2ecd71f6ab04 357 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 358 }
janjongboom 0:2ecd71f6ab04 359
janjongboom 0:2ecd71f6ab04 360
janjongboom 0:2ecd71f6ab04 361
janjongboom 0:2ecd71f6ab04 362 template <typename T>
janjongboom 0:2ecd71f6ab04 363 SimpleChar<T> readWrite(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 364 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 365 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 366 T defaultValue = T(),
janjongboom 0:2ecd71f6ab04 367 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 368 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 369 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 370 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 371
janjongboom 0:2ecd71f6ab04 372 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 373 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback);
janjongboom 0:2ecd71f6ab04 374
janjongboom 0:2ecd71f6ab04 375 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 376
janjongboom 0:2ecd71f6ab04 377 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 378
janjongboom 0:2ecd71f6ab04 379 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 380 }
janjongboom 0:2ecd71f6ab04 381
janjongboom 0:2ecd71f6ab04 382 template <typename T>
janjongboom 0:2ecd71f6ab04 383 SimpleChar<T> readWrite(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 384 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 385 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 386 return readWrite(serviceUuid, charUuid, true, T(), callback);
janjongboom 0:2ecd71f6ab04 387 }
janjongboom 0:2ecd71f6ab04 388
janjongboom 0:2ecd71f6ab04 389 template <typename T>
janjongboom 0:2ecd71f6ab04 390 SimpleChar<T> readWrite(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 391 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 392 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 393 return readWrite(serviceUuid, charUuid, true, T(), callback);
janjongboom 0:2ecd71f6ab04 394 }
janjongboom 0:2ecd71f6ab04 395
janjongboom 0:2ecd71f6ab04 396 // === END READWRITE ===
janjongboom 0:2ecd71f6ab04 397
janjongboom 0:2ecd71f6ab04 398 // === START WRITEONLY ===
janjongboom 0:2ecd71f6ab04 399
janjongboom 0:2ecd71f6ab04 400 template <typename T>
janjongboom 0:2ecd71f6ab04 401 SimpleChar<T> writeOnly(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 402 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 403 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 404 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c =
janjongboom 1:17c8f5afa7bc 405 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback);
janjongboom 0:2ecd71f6ab04 406
janjongboom 0:2ecd71f6ab04 407 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 408
janjongboom 0:2ecd71f6ab04 409 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 410
janjongboom 0:2ecd71f6ab04 411 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 412 }
janjongboom 0:2ecd71f6ab04 413
janjongboom 0:2ecd71f6ab04 414 template <typename T>
janjongboom 0:2ecd71f6ab04 415 SimpleChar<T> writeOnly(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 416 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 417 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 418
janjongboom 0:2ecd71f6ab04 419 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c =
janjongboom 1:17c8f5afa7bc 420 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback);
janjongboom 0:2ecd71f6ab04 421
janjongboom 0:2ecd71f6ab04 422 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 423
janjongboom 0:2ecd71f6ab04 424 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 425
janjongboom 0:2ecd71f6ab04 426 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 427 }
janjongboom 0:2ecd71f6ab04 428
janjongboom 1:17c8f5afa7bc 429 // === END WRITEONLY ===
janjongboom 0:2ecd71f6ab04 430
janjongboom 0:2ecd71f6ab04 431 BLE* ble;
janjongboom 0:2ecd71f6ab04 432 const char* name;
janjongboom 0:2ecd71f6ab04 433 uint16_t interval;
janjongboom 1:17c8f5afa7bc 434 bool logging;
janjongboom 0:2ecd71f6ab04 435 map<uint16_t, vector<GattCharacteristic*>* > uint16_services;
janjongboom 0:2ecd71f6ab04 436 map<string, vector<GattCharacteristic*>* > uint128_services;
janjongboom 0:2ecd71f6ab04 437 map<GattCharacteristic*, Updatable*> writeCallbacks;
janjongboom 0:2ecd71f6ab04 438 };
janjongboom 0:2ecd71f6ab04 439