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:37:38 2016 +0000
Revision:
2:15329a3de04c
Parent:
1:17c8f5afa7bc
Child:
4:0c99ff9d2373
Add float

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 2:15329a3de04c 203 def_fn(float, float)
janjongboom 1:17c8f5afa7bc 204
janjongboom 1:17c8f5afa7bc 205 private:
janjongboom 1:17c8f5afa7bc 206 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
janjongboom 1:17c8f5afa7bc 207 {
janjongboom 1:17c8f5afa7bc 208 if (logging) printf("bleInitComplete\r\n");
janjongboom 1:17c8f5afa7bc 209
janjongboom 1:17c8f5afa7bc 210 BLE& ble = params->ble;
janjongboom 1:17c8f5afa7bc 211 ble_error_t error = params->error;
janjongboom 1:17c8f5afa7bc 212
janjongboom 1:17c8f5afa7bc 213 if (error != BLE_ERROR_NONE) {
janjongboom 1:17c8f5afa7bc 214 if (logging) printf("BLE Init error %d\r\n", error);
janjongboom 1:17c8f5afa7bc 215 return;
janjongboom 1:17c8f5afa7bc 216 }
janjongboom 1:17c8f5afa7bc 217
janjongboom 1:17c8f5afa7bc 218 /* Ensure that it is the default instance of BLE */
janjongboom 1:17c8f5afa7bc 219 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
janjongboom 1:17c8f5afa7bc 220 return;
janjongboom 1:17c8f5afa7bc 221 }
janjongboom 1:17c8f5afa7bc 222
janjongboom 1:17c8f5afa7bc 223 ble.gattServer().onDataWritten(this, &SimpleBLE::onDataWrittenCallback);
janjongboom 1:17c8f5afa7bc 224
janjongboom 1:17c8f5afa7bc 225 // let's add some services yo (why is there no 'auto' in mbed?)
janjongboom 1:17c8f5afa7bc 226 uint16_t uuid16_list[uint16_services.size()];
janjongboom 1:17c8f5afa7bc 227 size_t uuid16_counter = 0;
janjongboom 1:17c8f5afa7bc 228 {
janjongboom 1:17c8f5afa7bc 229 typedef std::map<uint16_t, vector<GattCharacteristic*>* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 230 for(it_type it = uint16_services.begin(); it != uint16_services.end(); it++) {
janjongboom 1:17c8f5afa7bc 231 if (logging) printf("Creating service 0x%x\n", it->first);
janjongboom 1:17c8f5afa7bc 232 uuid16_list[uuid16_counter++] = it->first;
janjongboom 1:17c8f5afa7bc 233
janjongboom 1:17c8f5afa7bc 234 GattCharacteristic* charTable[it->second->size()];
janjongboom 1:17c8f5afa7bc 235 for (size_t git = 0; git < it->second->size(); git++) {
janjongboom 1:17c8f5afa7bc 236 charTable[git] = it->second->at(git);
janjongboom 1:17c8f5afa7bc 237 }
janjongboom 1:17c8f5afa7bc 238
janjongboom 1:17c8f5afa7bc 239 GattService service(it->first, charTable, it->second->size());
janjongboom 1:17c8f5afa7bc 240 ble.gattServer().addService(service);
janjongboom 1:17c8f5afa7bc 241 }
janjongboom 1:17c8f5afa7bc 242 }
janjongboom 1:17c8f5afa7bc 243
janjongboom 1:17c8f5afa7bc 244 // 128 Bit services
janjongboom 1:17c8f5afa7bc 245 const char* uuid128_list[uint128_services.size()];
janjongboom 1:17c8f5afa7bc 246 size_t uuid128_counter = 0;
janjongboom 1:17c8f5afa7bc 247 {
janjongboom 1:17c8f5afa7bc 248 typedef std::map<string, vector<GattCharacteristic*>* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 249 for(it_type it = uint128_services.begin(); it != uint128_services.end(); it++) {
janjongboom 1:17c8f5afa7bc 250 if (logging) printf("Creating service %s\n", it->first.c_str());
janjongboom 1:17c8f5afa7bc 251 uuid128_list[uuid128_counter++] = it->first.c_str();
janjongboom 1:17c8f5afa7bc 252
janjongboom 1:17c8f5afa7bc 253 GattCharacteristic* charTable[it->second->size()];
janjongboom 1:17c8f5afa7bc 254 for (size_t git = 0; git < it->second->size(); git++) {
janjongboom 1:17c8f5afa7bc 255 charTable[git] = it->second->at(git);
janjongboom 1:17c8f5afa7bc 256 }
janjongboom 1:17c8f5afa7bc 257
janjongboom 1:17c8f5afa7bc 258 GattService service(UUID(it->first.c_str()), charTable, it->second->size());
janjongboom 1:17c8f5afa7bc 259 ble.gattServer().addService(service);
janjongboom 1:17c8f5afa7bc 260 }
janjongboom 1:17c8f5afa7bc 261 }
janjongboom 1:17c8f5afa7bc 262
janjongboom 1:17c8f5afa7bc 263 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
janjongboom 1:17c8f5afa7bc 264 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, uuid16_counter);
janjongboom 1:17c8f5afa7bc 265 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t *)uuid128_list, uuid128_counter);
janjongboom 1:17c8f5afa7bc 266 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)name, strlen(name));
janjongboom 1:17c8f5afa7bc 267 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
janjongboom 1:17c8f5afa7bc 268 ble.gap().setAdvertisingInterval(interval);
janjongboom 1:17c8f5afa7bc 269 ble.gap().startAdvertising();
janjongboom 1:17c8f5afa7bc 270
janjongboom 1:17c8f5afa7bc 271 if (logging) printf("Started advertising\r\n");
janjongboom 1:17c8f5afa7bc 272 }
janjongboom 1:17c8f5afa7bc 273
janjongboom 1:17c8f5afa7bc 274 void onDataWrittenCallback(const GattWriteCallbackParams *params) {
janjongboom 1:17c8f5afa7bc 275 // see if we know for which char this message is...
janjongboom 1:17c8f5afa7bc 276 typedef std::map<GattCharacteristic*, Updatable* >::iterator it_type;
janjongboom 1:17c8f5afa7bc 277 for(it_type it = writeCallbacks.begin(); it != writeCallbacks.end(); it++) {
janjongboom 1:17c8f5afa7bc 278 if (it->first->getValueHandle() == params->handle) {
janjongboom 1:17c8f5afa7bc 279 it->second->onDataWritten(params->data, params->len);
janjongboom 1:17c8f5afa7bc 280 }
janjongboom 1:17c8f5afa7bc 281 }
janjongboom 1:17c8f5afa7bc 282 }
janjongboom 1:17c8f5afa7bc 283
janjongboom 1:17c8f5afa7bc 284 void addToServices(uint16_t uuid, GattCharacteristic* c) {
janjongboom 1:17c8f5afa7bc 285 if (uint16_services.count(uuid) == 0) {
janjongboom 1:17c8f5afa7bc 286 uint16_services[uuid] = new vector<GattCharacteristic*>();
janjongboom 1:17c8f5afa7bc 287 }
janjongboom 1:17c8f5afa7bc 288
janjongboom 1:17c8f5afa7bc 289 uint16_services[uuid]->push_back(c);
janjongboom 1:17c8f5afa7bc 290 }
janjongboom 1:17c8f5afa7bc 291
janjongboom 1:17c8f5afa7bc 292 void addToServices(const char* aUuid, GattCharacteristic* c) {
janjongboom 1:17c8f5afa7bc 293 string uuid(aUuid);
janjongboom 1:17c8f5afa7bc 294 if (uint128_services.count(uuid) == 0) {
janjongboom 1:17c8f5afa7bc 295 uint128_services[uuid] = new vector<GattCharacteristic*>();
janjongboom 1:17c8f5afa7bc 296 }
janjongboom 1:17c8f5afa7bc 297
janjongboom 1:17c8f5afa7bc 298 uint128_services[uuid]->push_back(c);
janjongboom 0:2ecd71f6ab04 299 }
janjongboom 0:2ecd71f6ab04 300
janjongboom 0:2ecd71f6ab04 301 // === START READONLY ===
janjongboom 0:2ecd71f6ab04 302
janjongboom 0:2ecd71f6ab04 303 template <typename T>
janjongboom 0:2ecd71f6ab04 304 SimpleChar<T> readOnly(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 305 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 306 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 307 T defaultValue = T()) {
janjongboom 0:2ecd71f6ab04 308 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 309 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 310 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 311
janjongboom 0:2ecd71f6ab04 312 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 313 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue);
janjongboom 0:2ecd71f6ab04 314
janjongboom 0:2ecd71f6ab04 315 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 316
janjongboom 0:2ecd71f6ab04 317 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 318 }
janjongboom 0:2ecd71f6ab04 319
janjongboom 0:2ecd71f6ab04 320 template <typename T>
janjongboom 0:2ecd71f6ab04 321 SimpleChar<T> readOnly(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 322 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 323 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 324 T defaultValue = T()) {
janjongboom 0:2ecd71f6ab04 325 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 326 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 327 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 328
janjongboom 0:2ecd71f6ab04 329 SimpleCharInternal<T, ReadOnlyGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 330 new SimpleCharInternal<T, ReadOnlyGattCharacteristic>(ble, charUuid, gattChar, defaultValue);
janjongboom 0:2ecd71f6ab04 331
janjongboom 0:2ecd71f6ab04 332 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 333
janjongboom 0:2ecd71f6ab04 334 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 335 }
janjongboom 0:2ecd71f6ab04 336
janjongboom 0:2ecd71f6ab04 337 // === END READONLY ===
janjongboom 0:2ecd71f6ab04 338
janjongboom 0:2ecd71f6ab04 339 // === START READWRITE ===
janjongboom 0:2ecd71f6ab04 340
janjongboom 0:2ecd71f6ab04 341 template <typename T>
janjongboom 0:2ecd71f6ab04 342 SimpleChar<T> readWrite(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 343 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 344 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 345 T defaultValue = T(),
janjongboom 0:2ecd71f6ab04 346 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 347 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 348 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 349 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 350
janjongboom 0:2ecd71f6ab04 351 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 352 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback);
janjongboom 0:2ecd71f6ab04 353
janjongboom 0:2ecd71f6ab04 354 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 355
janjongboom 0:2ecd71f6ab04 356 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 357
janjongboom 0:2ecd71f6ab04 358 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 359 }
janjongboom 0:2ecd71f6ab04 360
janjongboom 0:2ecd71f6ab04 361
janjongboom 0:2ecd71f6ab04 362
janjongboom 0:2ecd71f6ab04 363 template <typename T>
janjongboom 0:2ecd71f6ab04 364 SimpleChar<T> readWrite(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 365 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 366 bool enableNotify = true,
janjongboom 0:2ecd71f6ab04 367 T defaultValue = T(),
janjongboom 0:2ecd71f6ab04 368 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 369 GattCharacteristic::Properties_t gattChar = enableNotify ?
janjongboom 0:2ecd71f6ab04 370 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY :
janjongboom 0:2ecd71f6ab04 371 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ;
janjongboom 0:2ecd71f6ab04 372
janjongboom 0:2ecd71f6ab04 373 SimpleCharInternal<T, ReadWriteGattCharacteristic>* c =
janjongboom 0:2ecd71f6ab04 374 new SimpleCharInternal<T, ReadWriteGattCharacteristic>(ble, charUuid, gattChar, defaultValue, callback);
janjongboom 0:2ecd71f6ab04 375
janjongboom 0:2ecd71f6ab04 376 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 377
janjongboom 0:2ecd71f6ab04 378 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 379
janjongboom 0:2ecd71f6ab04 380 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 381 }
janjongboom 0:2ecd71f6ab04 382
janjongboom 0:2ecd71f6ab04 383 template <typename T>
janjongboom 0:2ecd71f6ab04 384 SimpleChar<T> readWrite(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 385 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 386 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 387 return readWrite(serviceUuid, charUuid, true, T(), callback);
janjongboom 0:2ecd71f6ab04 388 }
janjongboom 0:2ecd71f6ab04 389
janjongboom 0:2ecd71f6ab04 390 template <typename T>
janjongboom 0:2ecd71f6ab04 391 SimpleChar<T> readWrite(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 392 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 393 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 394 return readWrite(serviceUuid, charUuid, true, T(), callback);
janjongboom 0:2ecd71f6ab04 395 }
janjongboom 0:2ecd71f6ab04 396
janjongboom 0:2ecd71f6ab04 397 // === END READWRITE ===
janjongboom 0:2ecd71f6ab04 398
janjongboom 0:2ecd71f6ab04 399 // === START WRITEONLY ===
janjongboom 0:2ecd71f6ab04 400
janjongboom 0:2ecd71f6ab04 401 template <typename T>
janjongboom 0:2ecd71f6ab04 402 SimpleChar<T> writeOnly(uint16_t serviceUuid,
janjongboom 0:2ecd71f6ab04 403 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 404 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 405 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c =
janjongboom 1:17c8f5afa7bc 406 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback);
janjongboom 0:2ecd71f6ab04 407
janjongboom 0:2ecd71f6ab04 408 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 409
janjongboom 0:2ecd71f6ab04 410 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 411
janjongboom 0:2ecd71f6ab04 412 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 413 }
janjongboom 0:2ecd71f6ab04 414
janjongboom 0:2ecd71f6ab04 415 template <typename T>
janjongboom 0:2ecd71f6ab04 416 SimpleChar<T> writeOnly(const char* serviceUuid,
janjongboom 0:2ecd71f6ab04 417 const UUID& charUuid,
janjongboom 0:2ecd71f6ab04 418 void(*callback)(T) = NULL) {
janjongboom 0:2ecd71f6ab04 419
janjongboom 0:2ecd71f6ab04 420 SimpleCharInternal<T, WriteOnlyGattCharacteristic>* c =
janjongboom 1:17c8f5afa7bc 421 new SimpleCharInternal<T, WriteOnlyGattCharacteristic>(ble, charUuid, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NONE, T(), callback);
janjongboom 0:2ecd71f6ab04 422
janjongboom 0:2ecd71f6ab04 423 addToServices(serviceUuid, c->getChar());
janjongboom 0:2ecd71f6ab04 424
janjongboom 0:2ecd71f6ab04 425 writeCallbacks[c->getChar()] = c;
janjongboom 0:2ecd71f6ab04 426
janjongboom 0:2ecd71f6ab04 427 return *(new SimpleChar<T>(c));
janjongboom 0:2ecd71f6ab04 428 }
janjongboom 0:2ecd71f6ab04 429
janjongboom 1:17c8f5afa7bc 430 // === END WRITEONLY ===
janjongboom 0:2ecd71f6ab04 431
janjongboom 0:2ecd71f6ab04 432 BLE* ble;
janjongboom 0:2ecd71f6ab04 433 const char* name;
janjongboom 0:2ecd71f6ab04 434 uint16_t interval;
janjongboom 1:17c8f5afa7bc 435 bool logging;
janjongboom 0:2ecd71f6ab04 436 map<uint16_t, vector<GattCharacteristic*>* > uint16_services;
janjongboom 0:2ecd71f6ab04 437 map<string, vector<GattCharacteristic*>* > uint128_services;
janjongboom 0:2ecd71f6ab04 438 map<GattCharacteristic*, Updatable*> writeCallbacks;
janjongboom 0:2ecd71f6ab04 439 };
janjongboom 0:2ecd71f6ab04 440