This example demonstrates using the GattClient API to control BLE client devices. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_LEDBlinker

BLE LED Blinker

This example demonstrates using the ``GattClient`` API to control BLE client devices.

The example uses two applications running on two different devices:

  • The first device - the central - runs the application ``BLE_LEDBlinker`` from this repository. This application sends an on/off toggle over BLE.
  • The second device - the peripheral - runs the application ``BLE_LED`` to respond to the toggle.

The toggle simply turns the LED on the peripheral device on and off.

Running the application

Requirements

Hardware requirements are in the main readme.

This example requires *two* devices.

Building instructions

You will need to build both applications and flash each one to a different board.

Please note: The application BLE_LEDBlinker in this repository initiate a connection to all ble devices which advertise "LED" as complete local name. By default, the application BLE_LED advertises "LED" as complete local name. If you change the local name advertised by the application BLE_LED you should reflect your change in this application by changing the value of the constant PEER_NAME in main.cpp.

Tip: You may notice that the application also checks the LED characteristic's UUID; you don't need to change this parameter's value, because it already matches the UUID provided by the second application, BLE_LED.

Building with mbed CLI

If you'd like to use mbed CLI to build this, then you should refer to the main readme. The instructions here relate to using the developer.mbed.org Online Compiler

In order to build this example in the mbed Online Compiler, first import the example using the ‘Import’ button on the right hand side.

Next, select a platform to build for. This must either be a platform that supports BLE, for example the NRF51-DK, or one of the following:

List of platforms supporting Bluetooth Low Energy

Or you must also add a piece of hardware and the supporting library that includes a Bluetooth Low Energy driver for that hardware, for example the K64F or NUCLEO_F401RE with the X-NUCLEO-IDB05A1

List of components supporting Bluetooth Low Energy.

Once you have selected your platform, compile the example and drag and drop the resulting binary onto your board.

For general instructions on using the mbed Online Compiler, please see the mbed Handbook

Checking for success

  • Build both applications and install one on each device, as explained in the building instructions.
  • The LED number two of the device running ``BLE_LED`` should blink.

Monitoring the application through a serial port

You can run ``BLE_LEDBlinker`` and see that it works properly by monitoring its serial output.

You need a terminal program to listen to the output through a serial port. You can download one, for example:

  • Tera Term for Windows.
  • CoolTerm for Mac OS X.
  • GNU Screen for Linux.

To see the application's output:

  • Check which serial port your device is connected to.
  • Run a terminal program with the correct serial port and set the baud rate to 9600. For example, to use GNU Screen, run: ``screen /dev/tty.usbmodem1412 9600``.
  • The application should start printing the toggle's value to the terminal.

Note: ``BLE_LEDBlinker`` will not run properly if the ``BLE_LED`` application is not running on a second device. The terminal will show a few print statements, but you will not be able to see the application in full operation.

Committer:
mbed_official
Date:
Mon Oct 24 11:15:41 2016 +0100
Revision:
12:059c7b7fb18a
Parent:
4:9a6b0d5ea664
Child:
28:64621b6587e1
Merge pull request #32 from ARMmbed/oob

Sync with mbed OS 5.2 OOB repo

Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Vincent Coubard 0:86bf1d2040b3 1 /* mbed Microcontroller Library
Vincent Coubard 0:86bf1d2040b3 2 * Copyright (c) 2006-2015 ARM Limited
Vincent Coubard 0:86bf1d2040b3 3 *
Vincent Coubard 0:86bf1d2040b3 4 * Licensed under the Apache License, Version 2.0 (the "License");
Vincent Coubard 0:86bf1d2040b3 5 * you may not use this file except in compliance with the License.
Vincent Coubard 0:86bf1d2040b3 6 * You may obtain a copy of the License at
Vincent Coubard 0:86bf1d2040b3 7 *
Vincent Coubard 0:86bf1d2040b3 8 * http://www.apache.org/licenses/LICENSE-2.0
Vincent Coubard 0:86bf1d2040b3 9 *
Vincent Coubard 0:86bf1d2040b3 10 * Unless required by applicable law or agreed to in writing, software
Vincent Coubard 0:86bf1d2040b3 11 * distributed under the License is distributed on an "AS IS" BASIS,
Vincent Coubard 0:86bf1d2040b3 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Vincent Coubard 0:86bf1d2040b3 13 * See the License for the specific language governing permissions and
Vincent Coubard 0:86bf1d2040b3 14 * limitations under the License.
Vincent Coubard 0:86bf1d2040b3 15 */
Vincent Coubard 0:86bf1d2040b3 16
mbed_official 12:059c7b7fb18a 17 #include <events/mbed_events.h>
Vincent Coubard 0:86bf1d2040b3 18 #include <mbed.h>
Vincent Coubard 0:86bf1d2040b3 19 #include "ble/BLE.h"
Vincent Coubard 0:86bf1d2040b3 20 #include "ble/DiscoveredCharacteristic.h"
Vincent Coubard 0:86bf1d2040b3 21 #include "ble/DiscoveredService.h"
Vincent Coubard 0:86bf1d2040b3 22
Vincent Coubard 0:86bf1d2040b3 23 DigitalOut alivenessLED(LED1, 1);
Vincent Coubard 0:86bf1d2040b3 24 static DiscoveredCharacteristic ledCharacteristic;
Vincent Coubard 0:86bf1d2040b3 25 static bool triggerLedCharacteristic;
Vincent Coubard 0:86bf1d2040b3 26 static const char PEER_NAME[] = "LED";
Vincent Coubard 0:86bf1d2040b3 27
Vincent Coubard 0:86bf1d2040b3 28 static EventQueue eventQueue(
Vincent Coubard 0:86bf1d2040b3 29 /* event count */ 16 * /* event size */ 32
Vincent Coubard 0:86bf1d2040b3 30 );
Vincent Coubard 0:86bf1d2040b3 31
Vincent Coubard 0:86bf1d2040b3 32 void periodicCallback(void) {
Vincent Coubard 0:86bf1d2040b3 33 alivenessLED = !alivenessLED; /* Do blinky on LED1 while we're waiting for BLE events */
Vincent Coubard 0:86bf1d2040b3 34 }
Vincent Coubard 0:86bf1d2040b3 35
Vincent Coubard 0:86bf1d2040b3 36 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
Vincent Coubard 0:86bf1d2040b3 37 // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
Vincent Coubard 0:86bf1d2040b3 38 // The advertising payload is a collection of key/value records where
Vincent Coubard 0:86bf1d2040b3 39 // byte 0: length of the record excluding this byte
Vincent Coubard 0:86bf1d2040b3 40 // byte 1: The key, it is the type of the data
Vincent Coubard 0:86bf1d2040b3 41 // byte [2..N] The value. N is equal to byte0 - 1
Vincent Coubard 0:86bf1d2040b3 42 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
Vincent Coubard 0:86bf1d2040b3 43
Vincent Coubard 0:86bf1d2040b3 44 const uint8_t record_length = params->advertisingData[i];
Vincent Coubard 0:86bf1d2040b3 45 if (record_length == 0) {
Vincent Coubard 0:86bf1d2040b3 46 continue;
Vincent Coubard 0:86bf1d2040b3 47 }
Vincent Coubard 0:86bf1d2040b3 48 const uint8_t type = params->advertisingData[i + 1];
Vincent Coubard 0:86bf1d2040b3 49 const uint8_t* value = params->advertisingData + i + 2;
Vincent Coubard 0:86bf1d2040b3 50 const uint8_t value_length = record_length - 1;
Vincent Coubard 0:86bf1d2040b3 51
Vincent Coubard 0:86bf1d2040b3 52 if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
Vincent Coubard 0:86bf1d2040b3 53 if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) {
Vincent Coubard 0:86bf1d2040b3 54 printf(
Vincent Coubard 0:86bf1d2040b3 55 "adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
Vincent Coubard 0:86bf1d2040b3 56 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2],
Vincent Coubard 0:86bf1d2040b3 57 params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type
Vincent Coubard 0:86bf1d2040b3 58 );
Vincent Coubard 0:86bf1d2040b3 59 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
Vincent Coubard 0:86bf1d2040b3 60 break;
Vincent Coubard 0:86bf1d2040b3 61 }
Vincent Coubard 0:86bf1d2040b3 62 }
Vincent Coubard 0:86bf1d2040b3 63 i += record_length;
Vincent Coubard 0:86bf1d2040b3 64 }
Vincent Coubard 0:86bf1d2040b3 65 }
Vincent Coubard 0:86bf1d2040b3 66
Vincent Coubard 0:86bf1d2040b3 67 void serviceDiscoveryCallback(const DiscoveredService *service) {
Vincent Coubard 0:86bf1d2040b3 68 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
Vincent Coubard 0:86bf1d2040b3 69 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 70 } else {
Vincent Coubard 0:86bf1d2040b3 71 printf("S UUID-");
Vincent Coubard 0:86bf1d2040b3 72 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
Vincent Coubard 0:86bf1d2040b3 73 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
Vincent Coubard 0:86bf1d2040b3 74 printf("%02x", longUUIDBytes[i]);
Vincent Coubard 0:86bf1d2040b3 75 }
Vincent Coubard 0:86bf1d2040b3 76 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 77 }
Vincent Coubard 0:86bf1d2040b3 78 }
Vincent Coubard 0:86bf1d2040b3 79
Vincent Coubard 0:86bf1d2040b3 80 void updateLedCharacteristic(void) {
Vincent Coubard 0:86bf1d2040b3 81 if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
Vincent Coubard 0:86bf1d2040b3 82 ledCharacteristic.read();
Vincent Coubard 0:86bf1d2040b3 83 }
Vincent Coubard 0:86bf1d2040b3 84 }
Vincent Coubard 0:86bf1d2040b3 85
Vincent Coubard 0:86bf1d2040b3 86 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
Vincent Coubard 0:86bf1d2040b3 87 printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
Vincent Coubard 0:86bf1d2040b3 88 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
Vincent Coubard 0:86bf1d2040b3 89 ledCharacteristic = *characteristicP;
Vincent Coubard 0:86bf1d2040b3 90 triggerLedCharacteristic = true;
Vincent Coubard 0:86bf1d2040b3 91 }
Vincent Coubard 0:86bf1d2040b3 92 }
Vincent Coubard 0:86bf1d2040b3 93
Vincent Coubard 0:86bf1d2040b3 94 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
Vincent Coubard 0:86bf1d2040b3 95 printf("terminated SD for handle %u\r\n", connectionHandle);
Vincent Coubard 0:86bf1d2040b3 96 if (triggerLedCharacteristic) {
Vincent Coubard 0:86bf1d2040b3 97 triggerLedCharacteristic = false;
mbed_official 12:059c7b7fb18a 98 eventQueue.call(updateLedCharacteristic);
Vincent Coubard 0:86bf1d2040b3 99 }
Vincent Coubard 0:86bf1d2040b3 100 }
Vincent Coubard 0:86bf1d2040b3 101
Vincent Coubard 0:86bf1d2040b3 102 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
Vincent Coubard 0:86bf1d2040b3 103 if (params->role == Gap::CENTRAL) {
Vincent Coubard 0:86bf1d2040b3 104 BLE &ble = BLE::Instance();
Vincent Coubard 0:86bf1d2040b3 105 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
Vincent Coubard 0:86bf1d2040b3 106 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xa000, 0xa001);
Vincent Coubard 0:86bf1d2040b3 107 }
Vincent Coubard 0:86bf1d2040b3 108 }
Vincent Coubard 0:86bf1d2040b3 109
Vincent Coubard 0:86bf1d2040b3 110 void triggerToggledWrite(const GattReadCallbackParams *response) {
Vincent Coubard 0:86bf1d2040b3 111 if (response->handle == ledCharacteristic.getValueHandle()) {
Vincent Coubard 0:86bf1d2040b3 112 printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
Vincent Coubard 0:86bf1d2040b3 113 for (unsigned index = 0; index < response->len; index++) {
Vincent Coubard 0:86bf1d2040b3 114 printf("%c[%02x]", response->data[index], response->data[index]);
Vincent Coubard 0:86bf1d2040b3 115 }
Vincent Coubard 0:86bf1d2040b3 116 printf("\r\n");
Vincent Coubard 0:86bf1d2040b3 117
Vincent Coubard 0:86bf1d2040b3 118 uint8_t toggledValue = response->data[0] ^ 0x1;
Vincent Coubard 0:86bf1d2040b3 119 ledCharacteristic.write(1, &toggledValue);
Vincent Coubard 0:86bf1d2040b3 120 }
Vincent Coubard 0:86bf1d2040b3 121 }
Vincent Coubard 0:86bf1d2040b3 122
Vincent Coubard 0:86bf1d2040b3 123 void triggerRead(const GattWriteCallbackParams *response) {
Vincent Coubard 0:86bf1d2040b3 124 if (response->handle == ledCharacteristic.getValueHandle()) {
Vincent Coubard 0:86bf1d2040b3 125 ledCharacteristic.read();
Vincent Coubard 0:86bf1d2040b3 126 }
Vincent Coubard 0:86bf1d2040b3 127 }
Vincent Coubard 0:86bf1d2040b3 128
Vincent Coubard 0:86bf1d2040b3 129 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) {
Vincent Coubard 0:86bf1d2040b3 130 printf("disconnected\r\n");
Vincent Coubard 0:86bf1d2040b3 131 /* Start scanning and try to connect again */
Vincent Coubard 0:86bf1d2040b3 132 BLE::Instance().gap().startScan(advertisementCallback);
Vincent Coubard 0:86bf1d2040b3 133 }
Vincent Coubard 0:86bf1d2040b3 134
Vincent Coubard 0:86bf1d2040b3 135 void onBleInitError(BLE &ble, ble_error_t error)
Vincent Coubard 0:86bf1d2040b3 136 {
Vincent Coubard 0:86bf1d2040b3 137 /* Initialization error handling should go here */
Vincent Coubard 0:86bf1d2040b3 138 }
Vincent Coubard 0:86bf1d2040b3 139
Vincent Coubard 0:86bf1d2040b3 140 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
Vincent Coubard 0:86bf1d2040b3 141 {
Vincent Coubard 0:86bf1d2040b3 142 BLE& ble = params->ble;
Vincent Coubard 0:86bf1d2040b3 143 ble_error_t error = params->error;
Vincent Coubard 0:86bf1d2040b3 144
Vincent Coubard 0:86bf1d2040b3 145 if (error != BLE_ERROR_NONE) {
Vincent Coubard 0:86bf1d2040b3 146 /* In case of error, forward the error handling to onBleInitError */
Vincent Coubard 0:86bf1d2040b3 147 onBleInitError(ble, error);
Vincent Coubard 0:86bf1d2040b3 148 return;
Vincent Coubard 0:86bf1d2040b3 149 }
Vincent Coubard 0:86bf1d2040b3 150
Vincent Coubard 0:86bf1d2040b3 151 /* Ensure that it is the default instance of BLE */
Vincent Coubard 0:86bf1d2040b3 152 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
Vincent Coubard 0:86bf1d2040b3 153 return;
Vincent Coubard 0:86bf1d2040b3 154 }
Vincent Coubard 0:86bf1d2040b3 155
Vincent Coubard 0:86bf1d2040b3 156 ble.gap().onDisconnection(disconnectionCallback);
Vincent Coubard 0:86bf1d2040b3 157 ble.gap().onConnection(connectionCallback);
Vincent Coubard 0:86bf1d2040b3 158
Vincent Coubard 0:86bf1d2040b3 159 ble.gattClient().onDataRead(triggerToggledWrite);
Vincent Coubard 0:86bf1d2040b3 160 ble.gattClient().onDataWrite(triggerRead);
Vincent Coubard 0:86bf1d2040b3 161
Vincent Coubard 0:86bf1d2040b3 162 // scan interval: 400ms and scan window: 400ms.
Vincent Coubard 0:86bf1d2040b3 163 // Every 400ms the device will scan for 400ms
Vincent Coubard 0:86bf1d2040b3 164 // This means that the device will scan continuously.
Vincent Coubard 0:86bf1d2040b3 165 ble.gap().setScanParams(400, 400);
Vincent Coubard 0:86bf1d2040b3 166 ble.gap().startScan(advertisementCallback);
Vincent Coubard 0:86bf1d2040b3 167 }
Vincent Coubard 0:86bf1d2040b3 168
Vincent Coubard 0:86bf1d2040b3 169 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
Vincent Coubard 0:86bf1d2040b3 170 BLE &ble = BLE::Instance();
mbed_official 12:059c7b7fb18a 171 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
Vincent Coubard 0:86bf1d2040b3 172 }
Vincent Coubard 0:86bf1d2040b3 173
Vincent Coubard 0:86bf1d2040b3 174 int main()
Vincent Coubard 0:86bf1d2040b3 175 {
Vincent Coubard 0:86bf1d2040b3 176 triggerLedCharacteristic = false;
mbed_official 12:059c7b7fb18a 177 eventQueue.call_every(500, periodicCallback);
Vincent Coubard 0:86bf1d2040b3 178
Vincent Coubard 0:86bf1d2040b3 179 BLE &ble = BLE::Instance();
Vincent Coubard 0:86bf1d2040b3 180 ble.onEventsToProcess(scheduleBleEventsProcessing);
Vincent Coubard 0:86bf1d2040b3 181 ble.init(bleInitComplete);
Vincent Coubard 0:86bf1d2040b3 182
mbed_official 12:059c7b7fb18a 183 eventQueue.dispatch_forever();
Vincent Coubard 0:86bf1d2040b3 184
Vincent Coubard 0:86bf1d2040b3 185 return 0;
Vincent Coubard 0:86bf1d2040b3 186 }