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:
Wed May 11 12:59:14 2016 +0000
Revision:
0:2ecd71f6ab04
Child:
1:17c8f5afa7bc
SimpleBLE Initial Commit

Who changed what in which revision?

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