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:
Thu Aug 15 17:02:05 2019 +0100
Revision:
81:653db77bffd4
Parent:
77:85a0d3cdd896
Merge pull request #252 from donatieng/mbed_os_update

Update Master branch to use Mbed OS 5.13.1
.
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"
mbed_official 75:1a8d19363522 22 #include "ble/gap/Gap.h"
mbed_official 75:1a8d19363522 23 #include "ble/gap/AdvertisingDataParser.h"
mbed_official 75:1a8d19363522 24 #include "pretty_printer.h"
Vincent Coubard 0:86bf1d2040b3 25
mbed_official 75:1a8d19363522 26 const static char PEER_NAME[] = "LED";
Vincent Coubard 0:86bf1d2040b3 27
mbed_official 75:1a8d19363522 28 static EventQueue event_queue(/* event count */ 10 * EVENTS_EVENT_SIZE);
Vincent Coubard 0:86bf1d2040b3 29
mbed_official 75:1a8d19363522 30 static DiscoveredCharacteristic led_characteristic;
mbed_official 75:1a8d19363522 31 static bool trigger_led_characteristic = false;
Vincent Coubard 0:86bf1d2040b3 32
mbed_official 75:1a8d19363522 33 void service_discovery(const DiscoveredService *service) {
Vincent Coubard 0:86bf1d2040b3 34 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
Vincent Coubard 0:86bf1d2040b3 35 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 36 } else {
Vincent Coubard 0:86bf1d2040b3 37 printf("S UUID-");
Vincent Coubard 0:86bf1d2040b3 38 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
Vincent Coubard 0:86bf1d2040b3 39 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
Vincent Coubard 0:86bf1d2040b3 40 printf("%02x", longUUIDBytes[i]);
Vincent Coubard 0:86bf1d2040b3 41 }
Vincent Coubard 0:86bf1d2040b3 42 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
Vincent Coubard 0:86bf1d2040b3 43 }
Vincent Coubard 0:86bf1d2040b3 44 }
Vincent Coubard 0:86bf1d2040b3 45
mbed_official 75:1a8d19363522 46 void update_led_characteristic(void) {
Vincent Coubard 0:86bf1d2040b3 47 if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
mbed_official 75:1a8d19363522 48 led_characteristic.read();
Vincent Coubard 0:86bf1d2040b3 49 }
Vincent Coubard 0:86bf1d2040b3 50 }
Vincent Coubard 0:86bf1d2040b3 51
mbed_official 75:1a8d19363522 52 void characteristic_discovery(const DiscoveredCharacteristic *characteristicP) {
mbed_official 75:1a8d19363522 53 printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
mbed_official 75:1a8d19363522 54 if (characteristicP->getUUID().getShortUUID() == 0xa001) { /* !ALERT! Alter this filter to suit your device. */
mbed_official 75:1a8d19363522 55 led_characteristic = *characteristicP;
mbed_official 75:1a8d19363522 56 trigger_led_characteristic = true;
Vincent Coubard 0:86bf1d2040b3 57 }
Vincent Coubard 0:86bf1d2040b3 58 }
Vincent Coubard 0:86bf1d2040b3 59
mbed_official 75:1a8d19363522 60 void discovery_termination(Gap::Handle_t connectionHandle) {
mbed_official 75:1a8d19363522 61 printf("terminated SD for handle %u\r\n", connectionHandle);
mbed_official 75:1a8d19363522 62 if (trigger_led_characteristic) {
mbed_official 75:1a8d19363522 63 trigger_led_characteristic = false;
mbed_official 75:1a8d19363522 64 event_queue.call(update_led_characteristic);
Vincent Coubard 0:86bf1d2040b3 65 }
Vincent Coubard 0:86bf1d2040b3 66 }
Vincent Coubard 0:86bf1d2040b3 67
mbed_official 75:1a8d19363522 68 void trigger_toggled_write(const GattReadCallbackParams *response) {
mbed_official 75:1a8d19363522 69 if (response->handle == led_characteristic.getValueHandle()) {
mbed_official 75:1a8d19363522 70 printf("trigger_toggled_write: handle %u, offset %u, len %u\r\n", response->handle, response->offset, response->len);
Vincent Coubard 0:86bf1d2040b3 71 for (unsigned index = 0; index < response->len; index++) {
Vincent Coubard 0:86bf1d2040b3 72 printf("%c[%02x]", response->data[index], response->data[index]);
Vincent Coubard 0:86bf1d2040b3 73 }
Vincent Coubard 0:86bf1d2040b3 74 printf("\r\n");
Vincent Coubard 0:86bf1d2040b3 75
Vincent Coubard 0:86bf1d2040b3 76 uint8_t toggledValue = response->data[0] ^ 0x1;
mbed_official 75:1a8d19363522 77 led_characteristic.write(1, &toggledValue);
Vincent Coubard 0:86bf1d2040b3 78 }
Vincent Coubard 0:86bf1d2040b3 79 }
Vincent Coubard 0:86bf1d2040b3 80
mbed_official 75:1a8d19363522 81 void trigger_read(const GattWriteCallbackParams *response) {
mbed_official 75:1a8d19363522 82 if (response->handle == led_characteristic.getValueHandle()) {
mbed_official 75:1a8d19363522 83 led_characteristic.read();
Vincent Coubard 0:86bf1d2040b3 84 }
Vincent Coubard 0:86bf1d2040b3 85 }
Vincent Coubard 0:86bf1d2040b3 86
mbed_official 75:1a8d19363522 87 class LEDBlinkerDemo : ble::Gap::EventHandler {
mbed_official 75:1a8d19363522 88 public:
mbed_official 75:1a8d19363522 89 LEDBlinkerDemo(BLE &ble, events::EventQueue &event_queue) :
mbed_official 75:1a8d19363522 90 _ble(ble),
mbed_official 75:1a8d19363522 91 _event_queue(event_queue),
mbed_official 75:1a8d19363522 92 _alive_led(LED1, 1),
mbed_official 75:1a8d19363522 93 _actuated_led(LED2, 0),
mbed_official 75:1a8d19363522 94 _is_connecting(false) { }
Vincent Coubard 0:86bf1d2040b3 95
mbed_official 75:1a8d19363522 96 ~LEDBlinkerDemo() { }
mbed_official 75:1a8d19363522 97
mbed_official 75:1a8d19363522 98 void start() {
mbed_official 75:1a8d19363522 99 _ble.gap().setEventHandler(this);
mbed_official 75:1a8d19363522 100
mbed_official 75:1a8d19363522 101 _ble.init(this, &LEDBlinkerDemo::on_init_complete);
mbed_official 75:1a8d19363522 102
mbed_official 75:1a8d19363522 103 _event_queue.call_every(500, this, &LEDBlinkerDemo::blink);
mbed_official 75:1a8d19363522 104
mbed_official 75:1a8d19363522 105 _event_queue.dispatch_forever();
mbed_official 75:1a8d19363522 106 }
Vincent Coubard 0:86bf1d2040b3 107
mbed_official 75:1a8d19363522 108 private:
mbed_official 75:1a8d19363522 109 /** Callback triggered when the ble initialization process has finished */
mbed_official 75:1a8d19363522 110 void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
mbed_official 75:1a8d19363522 111 if (params->error != BLE_ERROR_NONE) {
mbed_official 75:1a8d19363522 112 printf("Ble initialization failed.");
mbed_official 75:1a8d19363522 113 return;
mbed_official 75:1a8d19363522 114 }
mbed_official 75:1a8d19363522 115
mbed_official 75:1a8d19363522 116 print_mac_address();
mbed_official 75:1a8d19363522 117
mbed_official 75:1a8d19363522 118 _ble.gattClient().onDataRead(trigger_toggled_write);
mbed_official 75:1a8d19363522 119 _ble.gattClient().onDataWritten(trigger_read);
mbed_official 75:1a8d19363522 120
mbed_official 75:1a8d19363522 121 ble::ScanParameters scan_params;
mbed_official 75:1a8d19363522 122 _ble.gap().setScanParameters(scan_params);
mbed_official 75:1a8d19363522 123 _ble.gap().startScan();
mbed_official 45:9fe6d1e21b8a 124 }
mbed_official 75:1a8d19363522 125
mbed_official 75:1a8d19363522 126 void blink() {
mbed_official 75:1a8d19363522 127 _alive_led = !_alive_led;
mbed_official 75:1a8d19363522 128 }
mbed_official 45:9fe6d1e21b8a 129
mbed_official 75:1a8d19363522 130 private:
mbed_official 75:1a8d19363522 131 /* Event handler */
Vincent Coubard 0:86bf1d2040b3 132
mbed_official 75:1a8d19363522 133 void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
mbed_official 75:1a8d19363522 134 _ble.gap().startScan();
mbed_official 75:1a8d19363522 135 _is_connecting = false;
Vincent Coubard 0:86bf1d2040b3 136 }
Vincent Coubard 0:86bf1d2040b3 137
mbed_official 75:1a8d19363522 138 void onConnectionComplete(const ble::ConnectionCompleteEvent& event) {
mbed_official 77:85a0d3cdd896 139 if (event.getOwnRole() == ble::connection_role_t::CENTRAL) {
mbed_official 75:1a8d19363522 140 _ble.gattClient().onServiceDiscoveryTermination(discovery_termination);
mbed_official 75:1a8d19363522 141 _ble.gattClient().launchServiceDiscovery(
mbed_official 75:1a8d19363522 142 event.getConnectionHandle(),
mbed_official 75:1a8d19363522 143 service_discovery,
mbed_official 75:1a8d19363522 144 characteristic_discovery,
mbed_official 75:1a8d19363522 145 0xa000,
mbed_official 75:1a8d19363522 146 0xa001
mbed_official 75:1a8d19363522 147 );
mbed_official 75:1a8d19363522 148 } else {
mbed_official 75:1a8d19363522 149 _ble.gap().startScan();
mbed_official 75:1a8d19363522 150 }
mbed_official 75:1a8d19363522 151 _is_connecting = false;
Vincent Coubard 0:86bf1d2040b3 152 }
Vincent Coubard 0:86bf1d2040b3 153
mbed_official 75:1a8d19363522 154 void onAdvertisingReport(const ble::AdvertisingReportEvent &event) {
mbed_official 75:1a8d19363522 155 /* don't bother with analysing scan result if we're already connecting */
mbed_official 75:1a8d19363522 156 if (_is_connecting) {
mbed_official 75:1a8d19363522 157 return;
mbed_official 75:1a8d19363522 158 }
mbed_official 75:1a8d19363522 159
mbed_official 75:1a8d19363522 160 ble::AdvertisingDataParser adv_data(event.getPayload());
mbed_official 75:1a8d19363522 161
mbed_official 75:1a8d19363522 162 /* parse the advertising payload, looking for a discoverable device */
mbed_official 75:1a8d19363522 163 while (adv_data.hasNext()) {
mbed_official 75:1a8d19363522 164 ble::AdvertisingDataParser::element_t field = adv_data.next();
Vincent Coubard 0:86bf1d2040b3 165
mbed_official 75:1a8d19363522 166 /* connect to a discoverable device */
mbed_official 75:1a8d19363522 167 if (field.type == ble::adv_data_type_t::COMPLETE_LOCAL_NAME &&
mbed_official 75:1a8d19363522 168 field.value.size() == strlen(PEER_NAME) &&
mbed_official 75:1a8d19363522 169 (memcmp(field.value.data(), PEER_NAME, field.value.size()) == 0)) {
mbed_official 75:1a8d19363522 170
mbed_official 75:1a8d19363522 171 printf("Adv from: ");
mbed_official 75:1a8d19363522 172 print_address(event.getPeerAddress().data());
mbed_official 75:1a8d19363522 173 printf(" rssi: %d, scan response: %u, connectable: %u\r\n",
mbed_official 75:1a8d19363522 174 event.getRssi(), event.getType().scan_response(), event.getType().connectable());
mbed_official 75:1a8d19363522 175
mbed_official 75:1a8d19363522 176 ble_error_t error = _ble.gap().stopScan();
mbed_official 75:1a8d19363522 177
mbed_official 75:1a8d19363522 178 if (error) {
mbed_official 75:1a8d19363522 179 print_error(error, "Error caused by Gap::stopScan");
mbed_official 75:1a8d19363522 180 return;
mbed_official 75:1a8d19363522 181 }
mbed_official 75:1a8d19363522 182
mbed_official 75:1a8d19363522 183 const ble::ConnectionParameters connection_params;
Vincent Coubard 0:86bf1d2040b3 184
mbed_official 75:1a8d19363522 185 error = _ble.gap().connect(
mbed_official 75:1a8d19363522 186 event.getPeerAddressType(),
mbed_official 75:1a8d19363522 187 event.getPeerAddress(),
mbed_official 75:1a8d19363522 188 connection_params
mbed_official 75:1a8d19363522 189 );
mbed_official 75:1a8d19363522 190
mbed_official 75:1a8d19363522 191 if (error) {
mbed_official 75:1a8d19363522 192 _ble.gap().startScan();
mbed_official 75:1a8d19363522 193 return;
mbed_official 75:1a8d19363522 194 }
mbed_official 75:1a8d19363522 195
mbed_official 75:1a8d19363522 196 /* we may have already scan events waiting
mbed_official 75:1a8d19363522 197 * to be processed so we need to remember
mbed_official 75:1a8d19363522 198 * that we are already connecting and ignore them */
mbed_official 75:1a8d19363522 199 _is_connecting = true;
mbed_official 45:9fe6d1e21b8a 200
mbed_official 75:1a8d19363522 201 return;
mbed_official 75:1a8d19363522 202 }
mbed_official 75:1a8d19363522 203 }
mbed_official 75:1a8d19363522 204 }
Vincent Coubard 0:86bf1d2040b3 205
mbed_official 75:1a8d19363522 206 private:
mbed_official 75:1a8d19363522 207 BLE &_ble;
mbed_official 75:1a8d19363522 208 events::EventQueue &_event_queue;
mbed_official 75:1a8d19363522 209 DigitalOut _alive_led;
mbed_official 75:1a8d19363522 210 DigitalOut _actuated_led;
mbed_official 75:1a8d19363522 211 bool _is_connecting;
mbed_official 75:1a8d19363522 212 };
mbed_official 75:1a8d19363522 213
mbed_official 75:1a8d19363522 214 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 75:1a8d19363522 215 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 75:1a8d19363522 216 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
Vincent Coubard 0:86bf1d2040b3 217 }
Vincent Coubard 0:86bf1d2040b3 218
Vincent Coubard 0:86bf1d2040b3 219 int main()
Vincent Coubard 0:86bf1d2040b3 220 {
mbed_official 75:1a8d19363522 221 BLE &ble = BLE::Instance();
mbed_official 75:1a8d19363522 222 ble.onEventsToProcess(schedule_ble_events);
Vincent Coubard 0:86bf1d2040b3 223
mbed_official 75:1a8d19363522 224 LEDBlinkerDemo demo(ble, event_queue);
mbed_official 75:1a8d19363522 225 demo.start();
Vincent Coubard 0:86bf1d2040b3 226
Vincent Coubard 0:86bf1d2040b3 227 return 0;
Vincent Coubard 0:86bf1d2040b3 228 }