Mistake on this page?
Submit a change in GitHub or email us

BLE

Bluetooth low energy (BLE) is a low power wireless technology standard for building personal area networks. Typical applications of BLE are health care, fitness trackers, beacons, smart home, security, entertainment, proximity sensors, industrial and automotive.

Arm Mbed BLE, also called BLE_API, is the Bluetooth Low Energy software solution for Mbed. Many Mbed targets and components support Mbed BLE. Developers can use it to create new BLE enabled applications.

Mbed’s BLE_API interfaces with the BLE controller on the platform. It hides the BLE stack’s complexity behind C++ abstractions and is compatible with all BLE-enabled Mbed platforms. The Mbed OS BLE_API automatically configuring the clocks, timers and other hardware peripherals to work at their lowest power consumption.

BLE_API, bridges and stacks

You can build a BLE application using Mbed OS, BLE_API and a controller-specific Bluetooth stack together with some bridge software to adapt it to BLE_API:

  • BLE_API as described above.
  • The bridge software is specific to each vendor’s platform. It provides the instantiations for the interfaces BLE_API offers and helps drive the underlying controller and Bluetooth stack.
  • The Bluetooth stack implements the Bluetooth protocol and is specific to the controller, so a vendor using different controllers may provide different stacks.

Inside BLE_API

BLE_API offers building blocks to help construct applications. These fall into two broad categories:

  1. Interfaces under ble/ to express BLE constructs, such as GAP, GATT, services and characteristics.

  2. Classes under ble/services to offer reference implementations for many of the commonly used GATT profiles. The code under 'services/' isn't essential, but it’s a useful starting point for prototyping. We continue to implement the standard GATT profiles.

The BLEDevice class and header

The entry point of Mbed's BLE_API is the BLE class accessible using the header ble/BLE.h. This class allows you to obtain a BLE object that includes the basic attributes of a spec-compatible BLE device and can work with any BLE radio:

#include "ble/BLE.h"

BLE& mydevicename = BLE::Instance();

The class's member functions can be divided by purpose:

  1. Basic BLE operations, such as initializing the controller.

  2. Accessor to Bluetooth Modules that manage GAP, GATT or the security.

Usage

  1. Set up advertising and connection modes.
  2. Assign UUIDs to the service and its characteristic.
  3. Create an input characteristic.
  4. Construct a service class and add it to the BLE stack.
  5. Push notifications when the characteristic's value changes.

BLE class reference

Data Structures
struct  InitializationCompleteCallbackContext
struct  OnEventsToProcessCallbackContext
Public Types
typedef unsigned InstanceID_t
typedef FunctionPointerWithContext< OnEventsToProcessCallbackContext * > OnEventsToProcessCallback_t
typedef void(* InitializationCompleteCallback_t) (InitializationCompleteCallbackContext *context)
Public Member Functions
InstanceID_t getInstanceID (void) const
void onEventsToProcess (const OnEventsToProcessCallback_t &on_event_cb)
void processEvents ()
ble_error_t init (InitializationCompleteCallback_t completion_cb=NULL)
template<typename T >
ble_error_t init (T *object, void(T::*completion_cb)(InitializationCompleteCallbackContext *context))
bool hasInitialized (void) const
ble_error_t shutdown (void)
const char * getVersion (void)
Gapgap ()
const Gapgap () const
GattServergattServer ()
const GattServergattServer () const
GattClientgattClient ()
const GattClientgattClient () const
SecurityManagersecurityManager ()
const SecurityManagersecurityManager () const
 BLE (InstanceID_t instanceID=DEFAULT_INSTANCE)
void waitForEvent (void)
ble_error_t setAddress (BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address)
ble_error_t getAddress (BLEProtocol::AddressType_t *typeP, BLEProtocol::AddressBytes_t address)
void setAdvertisingType (GapAdvertisingParams::AdvertisingType advType)
void setAdvertisingInterval (uint16_t interval)
uint16_t getMinAdvertisingInterval (void) const
uint16_t getMinNonConnectableAdvertisingInterval (void) const
uint16_t getMaxAdvertisingInterval (void) const
void setAdvertisingTimeout (uint16_t timeout)
void setAdvertisingParams (const GapAdvertisingParams &advParams)
const GapAdvertisingParamsgetAdvertisingParams (void) const
ble_error_t accumulateAdvertisingPayload (uint8_t flags)
ble_error_t accumulateAdvertisingPayload (GapAdvertisingData::Appearance app)
ble_error_t accumulateAdvertisingPayloadTxPower (int8_t power)
ble_error_t accumulateAdvertisingPayload (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
ble_error_t setAdvertisingData (const GapAdvertisingData &advData)
const GapAdvertisingDatagetAdvertisingData (void) const
void clearAdvertisingPayload (void)
ble_error_t setAdvertisingPayload (void)
ble_error_t accumulateScanResponse (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
void clearScanResponse (void)
ble_error_t startAdvertising (void)
ble_error_t stopAdvertising (void)
ble_error_t setScanParams (uint16_t interval=GapScanningParams::SCAN_INTERVAL_MAX, uint16_t window=GapScanningParams::SCAN_WINDOW_MAX, uint16_t timeout=0, bool activeScanning=false)
ble_error_t setScanInterval (uint16_t interval)
ble_error_t setScanWindow (uint16_t window)
ble_error_t setScanTimeout (uint16_t timeout)
void setActiveScan (bool activeScanning)
ble_error_t startScan (void(*callback)(const Gap::AdvertisementCallbackParams_t *params))
template<typename T >
ble_error_t startScan (T *object, void(T::*memberCallback)(const Gap::AdvertisementCallbackParams_t *params))
ble_error_t stopScan (void)
ble_error_t connect (const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t peerAddrType=BLEProtocol::AddressType::RANDOM_STATIC, const Gap::ConnectionParams_t *connectionParams=NULL, const GapScanningParams *scanParams=NULL)
ble_error_t disconnect (Gap::Handle_t connectionHandle, Gap::DisconnectionReason_t reason)
ble_error_t disconnect (Gap::DisconnectionReason_t reason)
Gap::GapState_t getGapState (void) const
ble_error_t getPreferredConnectionParams (Gap::ConnectionParams_t *params)
ble_error_t setPreferredConnectionParams (const Gap::ConnectionParams_t *params)
ble_error_t updateConnectionParams (Gap::Handle_t handle, const Gap::ConnectionParams_t *params)
ble_error_t setDeviceName (const uint8_t *deviceName)
ble_error_t getDeviceName (uint8_t *deviceName, unsigned *lengthP)
ble_error_t setAppearance (GapAdvertisingData::Appearance appearance)
ble_error_t getAppearance (GapAdvertisingData::Appearance *appearanceP)
ble_error_t setTxPower (int8_t txPower)
void getPermittedTxPowerValues (const int8_t **valueArrayPP, size_t *countP)
ble_error_t addService (GattService &service)
ble_error_t readCharacteristicValue (GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP)
ble_error_t readCharacteristicValue (Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, uint8_t *buffer, uint16_t *lengthP)
ble_error_t updateCharacteristicValue (GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly=false)
ble_error_t updateCharacteristicValue (Gap::Handle_t connectionHandle, GattAttribute::Handle_t attributeHandle, const uint8_t *value, uint16_t size, bool localOnly=false)
ble_error_t initializeSecurity (bool enableBonding=true, bool requireMITM=true, SecurityManager::SecurityIOCapabilities_t iocaps=SecurityManager::IO_CAPS_NONE, const SecurityManager::Passkey_t passkey=NULL)
ble_error_t getLinkSecurity (Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP)
ble_error_t purgeAllBondingState (void)
void onTimeout (Gap::TimeoutEventCallback_t timeoutCallback)
void onConnection (Gap::ConnectionEventCallback_t connectionCallback)
void onDisconnection (Gap::DisconnectionEventCallback_t disconnectionCallback)
template<typename T >
void onDisconnection (T *tptr, void(T::*mptr)(const Gap::DisconnectionCallbackParams_t *))
void onRadioNotification (void(*callback)(bool))
void onDataSent (void(*callback)(unsigned count))
template<typename T >
void onDataSent (T *objPtr, void(T::*memberPtr)(unsigned count))
void onDataWritten (void(*callback)(const GattWriteCallbackParams *eventDataP))
template<typename T >
void onDataWritten (T *objPtr, void(T::*memberPtr)(const GattWriteCallbackParams *context))
ble_error_t onDataRead (void(*callback)(const GattReadCallbackParams *eventDataP))
template<typename T >
ble_error_t onDataRead (T *objPtr, void(T::*memberPtr)(const GattReadCallbackParams *context))
void onUpdatesEnabled (GattServer::EventCallback_t callback)
void onUpdatesDisabled (GattServer::EventCallback_t callback)
void onConfirmationReceived (GattServer::EventCallback_t callback)
void onSecuritySetupInitiated (SecurityManager::SecuritySetupInitiatedCallback_t callback)
void onSecuritySetupCompleted (SecurityManager::SecuritySetupCompletedCallback_t callback)
void onLinkSecured (SecurityManager::LinkSecuredCallback_t callback)
void onSecurityContextStored (SecurityManager::HandleSpecificEvent_t callback)
void onPasskeyDisplay (SecurityManager::PasskeyDisplayCallback_t callback)
Static Public Member Functions
static BLEInstance (InstanceID_t id=DEFAULT_INSTANCE)
static const char * errorToString (ble_error_t error)
Static Public Attributes
static const InstanceID_t DEFAULT_INSTANCE = 0
static const InstanceID_t NUM_INSTANCES = 1
Friends
class BLEInstanceBase

Example: BLE beacon

Here is an example demonstrating how you can create a BLE beacon.

/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/services/iBeacon.h"

static iBeacon* ibeaconPtr;

static EventQueue eventQueue(/* event count */ 4 * EVENTS_EVENT_SIZE);

/**
 * This function is called when the ble initialization process has failled
 */
void onBleInitError(BLE &ble, ble_error_t error)
{
    /* Initialization error handling should go here */
}

void printMacAddress()
{
    /* Print out device MAC address to the console*/
    Gap::AddressType_t addr_type;
    Gap::Address_t address;
    BLE::Instance().gap().getAddress(&addr_type, address);
    printf("DEVICE MAC ADDRESS: ");
    for (int i = 5; i >= 1; i--){
        printf("%02x:", address[i]);
    }
    printf("%02x\r\n", address[0]);
}

/**
 * Callback triggered when the ble initialization process has finished
 */
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        /* In case of error, forward the error handling to onBleInitError */
        onBleInitError(ble, error);
        return;
    }

    /* Ensure that it is the default instance of BLE */
    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    /**
     * The Beacon payload has the following composition:
     * 128-Bit / 16byte UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
     * Major/Minor  = 0x1122 / 0x3344
     * Tx Power     = 0xC8 = 200, 2's compliment is 256-200 = (-56dB)
     *
     * Note: please remember to calibrate your beacons TX Power for more accurate results.
     */
    static const uint8_t uuid[] = {0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4,
                                   0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61};
    uint16_t majorNumber = 1122;
    uint16_t minorNumber = 3344;
    uint16_t txPower     = 0xC8;
    ibeaconPtr = new iBeacon(ble, uuid, majorNumber, minorNumber, txPower);

    ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
    ble.gap().startAdvertising();

    printMacAddress();
}

void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}

int main()
{
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(scheduleBleEventsProcessing);
    ble.init(bleInitComplete);

    eventQueue.dispatch_forever();

    return 0;
}

Example: BLE heart rate monitor

Here is an example demonstrating how to build a heart rate sensor that can be connected and monitored by a BLE client such as your phone.

/* mbed Microcontroller Library
 * Copyright (c) 2006-2015 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/services/HeartRateService.h"

DigitalOut led1(LED1, 1);

const static char     DEVICE_NAME[] = "HRM";
static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};

static uint8_t hrmCounter = 100; // init HRM to 100bps
static HeartRateService *hrServicePtr;

static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    BLE::Instance().gap().startAdvertising(); // restart advertising
}

void updateSensorValue() {
    // Do blocking calls or whatever is necessary for sensor polling.
    // In our case, we simply update the HRM measurement.
    hrmCounter++;

    //  100 <= HRM bps <=175
    if (hrmCounter == 175) {
        hrmCounter = 100;
    }

    hrServicePtr->updateHeartRate(hrmCounter);
}

void periodicCallback(void)
{
    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */

    if (BLE::Instance().getGapState().connected) {
        eventQueue.call(updateSensorValue);
    }
}

void onBleInitError(BLE &ble, ble_error_t error)
{
    (void)ble;
    (void)error;
   /* Initialization error handling should go here */
}

void printMacAddress()
{
    /* Print out device MAC address to the console*/
    Gap::AddressType_t addr_type;
    Gap::Address_t address;
    BLE::Instance().gap().getAddress(&addr_type, address);
    printf("DEVICE MAC ADDRESS: ");
    for (int i = 5; i >= 1; i--){
        printf("%02x:", address[i]);
    }
    printf("%02x\r\n", address[0]);
}

void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        onBleInitError(ble, error);
        return;
    }

    if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);

    /* Setup primary service. */
    hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);

    /* Setup advertising. */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
    ble.gap().startAdvertising();

    printMacAddress();
}

void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}

int main()
{
    eventQueue.call_every(500, periodicCallback);

    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(scheduleBleEventsProcessing);
    ble.init(bleInitComplete);

    eventQueue.dispatch_forever();

    return 0;
}