Bluetooth LE Communication¶
The CPP library does not implement Bluetooth LE communication; users must implement the GATT operations in their target language and pass those functions to the C++ API. The required GATT operations are defined as function pointers in the MblMwBtleConnection struct.
Read Characteristic¶
The first field in the struct is read_gatt_char
which points to the function reading the requested GATT characteristic. The function also
accepts a function pointer that the characteristic value will be passed to when the read operation completes.
#include <iomanip>
#include <iostream>
using namespace std;
static void read_gatt_char(const void* caller, const MblMwGattChar* characteristic,
MblMwFnIntVoidPtrArray handler) {
// replace with platform specific BluetoothGatt code
cout << setw(8) << setfill('0') << hex
<< "Reading characteristic: {service_uuid_high: " << characteristic->service_uuid_high
<< ", service_uuid_low: " << characteristic->service_uuid_low
<< ", uuid_high: " << characteristic->uuid_high
<< ", uuid_low: " << characteristic->uuid_low
<< "}" << dec << endl;
if (characteristic->uuid_high == 0x00002a2400001000 &&
characteristic->uuid_low == 0x800000805f9b34fb) {
// simulate response for reading model characteristic
const uint8_t model[] = "4";
handler(caller, model, 1);
} else if (characteristic->uuid_high == 0x00002a2600001000 &&
characteristic->uuid_low == 0x800000805f9b34fb) {
// simulate response for reading firmware characteristic
const uint8_t firmware[] = "1.2.5";
handler(caller, firmware, 5);
}
}
Write Characteristic¶
The next operation required by the SDK is writing GATT characteristics. When implementing the write function, note that there are two types of GATT writes defined by the MblMwGattCharWriteType enum. Your function must appropriately distinguish between the types when writing the GATT characteristic.
static void write_gatt_char(const void* caller, MblMwGattCharWriteType write_type,
const MblMwGattChar* characteristic, const uint8_t* value, uint8_t length) {
// replace with platform specific BluetoothGatt code
cout << "{write type: " << write_type << ", value: " <<
cout << hex << setw(2) << setfill('0') << "[0x" << (int)value[0];
for (uint8_t i = 1; i < length; i++) {
cout << ", 0x" << (int)value[i];
}
cout << "]}" << dec << endl;
}
Enabling Notifications¶
The C++ SDK uses the enable_char_notiy
function pointer to request characteristic notifications. Along with the characteristic to modify, the
function takes in 2 function pointers: the first one is run everytime the specific characteristic has changed and the latter is will be run when the
notify task is completed.
The ready
function pointer requires an additional int32 value that represents the status of the enable notify task. If sucessful, use the
MBL_MW_STATUS_OK
value and if it fails, use MBL_MW_STATUS_ERROR_ENABLE_NOTIFY
instead.
#include "metawear/core/status.h"
#include <unordered_map>
using std::unordered_map;
static unordered_map<const void*, MblMwFnIntVoidPtrArray> notify_handlers;
static void enable_char_notify(const void* caller, const MblMwGattChar* characteristic,
MblMwFnIntVoidPtrArray handler, MblMwFnVoidVoidPtrInt ready) {
// replace with platform specific BluetoothGatt code
notify_handlers.insert({ caller, handler });
// call the 'ready' function pointer when the enable notification requeset has finished
ready(caller, MBL_MW_STATUS_OK);
}
Disconnect Handler¶
The SDK also needs to know when the bluetooth connection is lost. It uses the on_disconnect
field to pass a function pointer to the Bluetooth LE
wrapper for handling disconnect events. The handler also accepts a second int value which, for now, can be set to 0.
static unordered_map<const void*, MblMwFnVoidVoidPtrInt> dc_handlers;
static void on_disconnect(const void* caller, MblMwFnVoidVoidPtrInt handler) {
// call this handler everytime connection is lost, use 0 for 'value' parameter
// handler(caller, 0)
dc_handlers.insert({ caller, handler });
}