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:
Wed May 10 10:17:12 2017 +0100
Revision:
28:64621b6587e1
Parent:
12:059c7b7fb18a
Child:
45:9fe6d1e21b8a
Merge pull request #78 from ashok-rao/master

Using predefined macro for EVENT SIZE.
.
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
mbed_official 28:64621b6587e1 28 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
Vincent Coubard 0:86bf1d2040b3 29
Vincent Coubard 0:86bf1d2040b3 30 void periodicCallback(void) {
Vincent Coubard 0:86bf1d2040b3 31 alivenessLED = !alivenessLED; /* Do blinky on LED1 while we're waiting for BLE events */
Vincent Coubard 0:86bf1d2040b3 32 }
Vincent Coubard 0:86bf1d2040b3 33
Vincent Coubard 0:86bf1d2040b3 34 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
Vincent Coubard 0:86bf1d2040b3 35 // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
Vincent Coubard 0:86bf1d2040b3 36 // The advertising payload is a collection of key/value records where
Vincent Coubard 0:86bf1d2040b3 37 // byte 0: length of the record excluding this byte
Vincent Coubard 0:86bf1d2040b3 38 // byte 1: The key, it is the type of the data
Vincent Coubard 0:86bf1d2040b3 39 // byte [2..N] The value. N is equal to byte0 - 1
Vincent Coubard 0:86bf1d2040b3 40 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
Vincent Coubard 0:86bf1d2040b3 41
Vincent Coubard 0:86bf1d2040b3 42 const uint8_t record_length = params->advertisingData[i];
Vincent Coubard 0:86bf1d2040b3 43 if (record_length == 0) {
Vincent Coubard 0:86bf1d2040b3 44 continue;
Vincent Coubard 0:86bf1d2040b3 45 }
Vincent Coubard 0:86bf1d2040b3 46 const uint8_t type = params->advertisingData[i + 1];
Vincent Coubard 0:86bf1d2040b3 47 const uint8_t* value = params->advertisingData + i + 2;
Vincent Coubard 0:86bf1d2040b3 48 const uint8_t value_length = record_length - 1;
Vincent Coubard 0:86bf1d2040b3 49
Vincent Coubard 0:86bf1d2040b3 50 if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
Vincent Coubard 0:86bf1d2040b3 51 if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) {
Vincent Coubard 0:86bf1d2040b3 52 printf(
Vincent Coubard 0:86bf1d2040b3 53 "adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
Vincent Coubard 0:86bf1d2040b3 54 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2],
Vincent Coubard 0:86bf1d2040b3 55 params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type
Vincent Coubard 0:86bf1d2040b3 56 );
Vincent Coubard 0:86bf1d2040b3 57 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
Vincent Coubard 0:86bf1d2040b3 58 break;
Vincent Coubard 0:86bf1d2040b3 59 }
Vincent Coubard 0:86bf1d2040b3 60 }
Vincent Coubard 0:86bf1d2040b3 61 i += record_length;
Vincent Coubard 0:86bf1d2040b3 62 }
Vincent Coubard 0:86bf1d2040b3 63 }
Vincent Coubard 0:86bf1d2040b3 64
Vincent Coubard 0:86bf1d2040b3 65 void serviceDiscoveryCallback(const DiscoveredService *service) {
Vincent Coubard 0:86bf1d2040b3 66 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
Vincent Coubard 0:86bf1d2040b3 67 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 68 } else {
Vincent Coubard 0:86bf1d2040b3 69 printf("S UUID-");
Vincent Coubard 0:86bf1d2040b3 70 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
Vincent Coubard 0:86bf1d2040b3 71 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
Vincent Coubard 0:86bf1d2040b3 72 printf("%02x", longUUIDBytes[i]);
Vincent Coubard 0:86bf1d2040b3 73 }
Vincent Coubard 0:86bf1d2040b3 74 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 75 }
Vincent Coubard 0:86bf1d2040b3 76 }
Vincent Coubard 0:86bf1d2040b3 77
Vincent Coubard 0:86bf1d2040b3 78 void updateLedCharacteristic(void) {
Vincent Coubard 0:86bf1d2040b3 79 if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
Vincent Coubard 0:86bf1d2040b3 80 ledCharacteristic.read();
Vincent Coubard 0:86bf1d2040b3 81 }
Vincent Coubard 0:86bf1d2040b3 82 }
Vincent Coubard 0:86bf1d2040b3 83
Vincent Coubard 0:86bf1d2040b3 84 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
Vincent Coubard 0:86bf1d2040b3 85 printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
Vincent Coubard 0:86bf1d2040b3 86 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
Vincent Coubard 0:86bf1d2040b3 87 ledCharacteristic = *characteristicP;
Vincent Coubard 0:86bf1d2040b3 88 triggerLedCharacteristic = true;
Vincent Coubard 0:86bf1d2040b3 89 }
Vincent Coubard 0:86bf1d2040b3 90 }
Vincent Coubard 0:86bf1d2040b3 91
Vincent Coubard 0:86bf1d2040b3 92 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
Vincent Coubard 0:86bf1d2040b3 93 printf("terminated SD for handle %u\r\n", connectionHandle);
Vincent Coubard 0:86bf1d2040b3 94 if (triggerLedCharacteristic) {
Vincent Coubard 0:86bf1d2040b3 95 triggerLedCharacteristic = false;
mbed_official 12:059c7b7fb18a 96 eventQueue.call(updateLedCharacteristic);
Vincent Coubard 0:86bf1d2040b3 97 }
Vincent Coubard 0:86bf1d2040b3 98 }
Vincent Coubard 0:86bf1d2040b3 99
Vincent Coubard 0:86bf1d2040b3 100 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
Vincent Coubard 0:86bf1d2040b3 101 if (params->role == Gap::CENTRAL) {
Vincent Coubard 0:86bf1d2040b3 102 BLE &ble = BLE::Instance();
Vincent Coubard 0:86bf1d2040b3 103 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
Vincent Coubard 0:86bf1d2040b3 104 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, 0xa000, 0xa001);
Vincent Coubard 0:86bf1d2040b3 105 }
Vincent Coubard 0:86bf1d2040b3 106 }
Vincent Coubard 0:86bf1d2040b3 107
Vincent Coubard 0:86bf1d2040b3 108 void triggerToggledWrite(const GattReadCallbackParams *response) {
Vincent Coubard 0:86bf1d2040b3 109 if (response->handle == ledCharacteristic.getValueHandle()) {
Vincent Coubard 0:86bf1d2040b3 110 printf("triggerToggledWrite: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
Vincent Coubard 0:86bf1d2040b3 111 for (unsigned index = 0; index < response->len; index++) {
Vincent Coubard 0:86bf1d2040b3 112 printf("%c[%02x]", response->data[index], response->data[index]);
Vincent Coubard 0:86bf1d2040b3 113 }
Vincent Coubard 0:86bf1d2040b3 114 printf("\r\n");
Vincent Coubard 0:86bf1d2040b3 115
Vincent Coubard 0:86bf1d2040b3 116 uint8_t toggledValue = response->data[0] ^ 0x1;
Vincent Coubard 0:86bf1d2040b3 117 ledCharacteristic.write(1, &toggledValue);
Vincent Coubard 0:86bf1d2040b3 118 }
Vincent Coubard 0:86bf1d2040b3 119 }
Vincent Coubard 0:86bf1d2040b3 120
Vincent Coubard 0:86bf1d2040b3 121 void triggerRead(const GattWriteCallbackParams *response) {
Vincent Coubard 0:86bf1d2040b3 122 if (response->handle == ledCharacteristic.getValueHandle()) {
Vincent Coubard 0:86bf1d2040b3 123 ledCharacteristic.read();
Vincent Coubard 0:86bf1d2040b3 124 }
Vincent Coubard 0:86bf1d2040b3 125 }
Vincent Coubard 0:86bf1d2040b3 126
Vincent Coubard 0:86bf1d2040b3 127 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) {
Vincent Coubard 0:86bf1d2040b3 128 printf("disconnected\r\n");
Vincent Coubard 0:86bf1d2040b3 129 /* Start scanning and try to connect again */
Vincent Coubard 0:86bf1d2040b3 130 BLE::Instance().gap().startScan(advertisementCallback);
Vincent Coubard 0:86bf1d2040b3 131 }
Vincent Coubard 0:86bf1d2040b3 132
Vincent Coubard 0:86bf1d2040b3 133 void onBleInitError(BLE &ble, ble_error_t error)
Vincent Coubard 0:86bf1d2040b3 134 {
Vincent Coubard 0:86bf1d2040b3 135 /* Initialization error handling should go here */
Vincent Coubard 0:86bf1d2040b3 136 }
Vincent Coubard 0:86bf1d2040b3 137
Vincent Coubard 0:86bf1d2040b3 138 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
Vincent Coubard 0:86bf1d2040b3 139 {
Vincent Coubard 0:86bf1d2040b3 140 BLE& ble = params->ble;
Vincent Coubard 0:86bf1d2040b3 141 ble_error_t error = params->error;
Vincent Coubard 0:86bf1d2040b3 142
Vincent Coubard 0:86bf1d2040b3 143 if (error != BLE_ERROR_NONE) {
Vincent Coubard 0:86bf1d2040b3 144 /* In case of error, forward the error handling to onBleInitError */
Vincent Coubard 0:86bf1d2040b3 145 onBleInitError(ble, error);
Vincent Coubard 0:86bf1d2040b3 146 return;
Vincent Coubard 0:86bf1d2040b3 147 }
Vincent Coubard 0:86bf1d2040b3 148
Vincent Coubard 0:86bf1d2040b3 149 /* Ensure that it is the default instance of BLE */
Vincent Coubard 0:86bf1d2040b3 150 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
Vincent Coubard 0:86bf1d2040b3 151 return;
Vincent Coubard 0:86bf1d2040b3 152 }
Vincent Coubard 0:86bf1d2040b3 153
Vincent Coubard 0:86bf1d2040b3 154 ble.gap().onDisconnection(disconnectionCallback);
Vincent Coubard 0:86bf1d2040b3 155 ble.gap().onConnection(connectionCallback);
Vincent Coubard 0:86bf1d2040b3 156
Vincent Coubard 0:86bf1d2040b3 157 ble.gattClient().onDataRead(triggerToggledWrite);
Vincent Coubard 0:86bf1d2040b3 158 ble.gattClient().onDataWrite(triggerRead);
Vincent Coubard 0:86bf1d2040b3 159
Vincent Coubard 0:86bf1d2040b3 160 // scan interval: 400ms and scan window: 400ms.
Vincent Coubard 0:86bf1d2040b3 161 // Every 400ms the device will scan for 400ms
Vincent Coubard 0:86bf1d2040b3 162 // This means that the device will scan continuously.
Vincent Coubard 0:86bf1d2040b3 163 ble.gap().setScanParams(400, 400);
Vincent Coubard 0:86bf1d2040b3 164 ble.gap().startScan(advertisementCallback);
Vincent Coubard 0:86bf1d2040b3 165 }
Vincent Coubard 0:86bf1d2040b3 166
Vincent Coubard 0:86bf1d2040b3 167 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
Vincent Coubard 0:86bf1d2040b3 168 BLE &ble = BLE::Instance();
mbed_official 12:059c7b7fb18a 169 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
Vincent Coubard 0:86bf1d2040b3 170 }
Vincent Coubard 0:86bf1d2040b3 171
Vincent Coubard 0:86bf1d2040b3 172 int main()
Vincent Coubard 0:86bf1d2040b3 173 {
Vincent Coubard 0:86bf1d2040b3 174 triggerLedCharacteristic = false;
mbed_official 12:059c7b7fb18a 175 eventQueue.call_every(500, periodicCallback);
Vincent Coubard 0:86bf1d2040b3 176
Vincent Coubard 0:86bf1d2040b3 177 BLE &ble = BLE::Instance();
Vincent Coubard 0:86bf1d2040b3 178 ble.onEventsToProcess(scheduleBleEventsProcessing);
Vincent Coubard 0:86bf1d2040b3 179 ble.init(bleInitComplete);
Vincent Coubard 0:86bf1d2040b3 180
mbed_official 12:059c7b7fb18a 181 eventQueue.dispatch_forever();
Vincent Coubard 0:86bf1d2040b3 182
Vincent Coubard 0:86bf1d2040b3 183 return 0;
Vincent Coubard 0:86bf1d2040b3 184 }