This example creates a BLE beacon: a method of advertising a small amount of information to nearby devices. The information doesn't have to be human-readable; it can be in a format that only an application can use. Beacons are very easy to set up: the code for all beacons is the same, and only the information you want to advertise - the beacon payload - needs to change. he canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_Beacon

This example creates a BLE beacon: a method of advertising a small amount of information to nearby devices. The information doesn't have to be human-readable; it can be in a format that only an application can use.

Beacons are very easy to set up: the code for all beacons is the same, and only the information you want to advertise - the beacon payload - needs to change.

This example advertises a UUID, a major and minor number and the transmission strength. The major and minor numbers are an example of information that is not (normally) meaningful to humans, but that an application can use to identify the beacon and display related information. For example, if the major number is a store ID and the minor number is a location in that store, then a matching application can use these numbers to query a database and display location-specific information.

Running the application

Requirements

The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install :

- nRF Master Control Panel for Android.

- LightBlue for iPhone.

Hardware requirements are in the main readme.

Building instructions

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

Note: Screens captures depicted below show what is expected from this example if the scanner used is nRF Master Control Panel version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals.

  • Build the application and install it on your board as explained in the building instructions.
  • Open the BLE scanner on your phone.
  • Start a scan.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-Beacon/raw-file/66b59f6860ed/img/start_scan.png

figure 1 How to start scan using nRF Master Control Panel 4.0.5

1. Find your device; it should be tagged as an `iBeacon` and observe its advertisements (there is no need to connect to the beacon).

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-Beacon/raw-file/66b59f6860ed/img/discovery.png

figure 2 Scan results using nRF Master Control Panel 4.0.5

  • View the beacon's details; the exact steps depend on which scanner you're using.

https://developer.mbed.org/teams/mbed-os-examples/code/mbed-os-example-ble-Beacon/raw-file/66b59f6860ed/img/beacon_details.png

figure 3 Beacon details using nRF Master Control Panel 4.0.5

Tip: If you are in an area with many BLE devices, it may be difficult to identify your beacon. The simplest solution is to turn your board off and on, initiate a new scan on your BLE scanner every time, and look for the beacon that appears only when your board is on.

If you can see the beacon and all its information, the application worked properly.

For more information, see the mbed Classic version of this application.

Committer:
mbed_official
Date:
Thu Aug 15 17:00:47 2019 +0100
Revision:
81:796f36bfa718
Parent:
76:652c2be531c7
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
mbed_official 3:41f6be68aefb 1 /* mbed Microcontroller Library
mbed_official 3:41f6be68aefb 2 * Copyright (c) 2006-2015 ARM Limited
mbed_official 3:41f6be68aefb 3 *
mbed_official 3:41f6be68aefb 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 3:41f6be68aefb 5 * you may not use this file except in compliance with the License.
mbed_official 3:41f6be68aefb 6 * You may obtain a copy of the License at
mbed_official 3:41f6be68aefb 7 *
mbed_official 3:41f6be68aefb 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 3:41f6be68aefb 9 *
mbed_official 3:41f6be68aefb 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 3:41f6be68aefb 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 3:41f6be68aefb 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 3:41f6be68aefb 13 * See the License for the specific language governing permissions and
mbed_official 3:41f6be68aefb 14 * limitations under the License.
mbed_official 3:41f6be68aefb 15 */
mbed_official 3:41f6be68aefb 16
mbed_official 12:af576944a152 17 #include <events/mbed_events.h>
mbed_official 3:41f6be68aefb 18 #include <mbed.h>
mbed_official 3:41f6be68aefb 19 #include "ble/BLE.h"
mbed_official 76:652c2be531c7 20 #include "pretty_printer.h"
mbed_official 3:41f6be68aefb 21
mbed_official 76:652c2be531c7 22 static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);
mbed_official 3:41f6be68aefb 23
mbed_official 76:652c2be531c7 24 /** @deprecated This demo is deprecated and no replacement is currently available.
mbed_official 76:652c2be531c7 25 */
mbed_official 76:652c2be531c7 26 MBED_DEPRECATED_SINCE(
mbed_official 76:652c2be531c7 27 "mbed-os-5.11",
mbed_official 76:652c2be531c7 28 "This demo is deprecated and no replacement is currently available."
mbed_official 76:652c2be531c7 29 )
mbed_official 76:652c2be531c7 30 class BeaconDemo : ble::Gap::EventHandler {
mbed_official 76:652c2be531c7 31 public:
mbed_official 76:652c2be531c7 32 BeaconDemo(BLE &ble, events::EventQueue &event_queue) :
mbed_official 76:652c2be531c7 33 _ble(ble),
mbed_official 76:652c2be531c7 34 _event_queue(event_queue),
mbed_official 76:652c2be531c7 35 _adv_data_builder(_adv_buffer) { }
mbed_official 45:0d307fc39fd0 36
mbed_official 76:652c2be531c7 37 void start() {
mbed_official 76:652c2be531c7 38 _ble.gap().setEventHandler(this);
mbed_official 3:41f6be68aefb 39
mbed_official 76:652c2be531c7 40 _ble.init(this, &BeaconDemo::on_init_complete);
mbed_official 76:652c2be531c7 41
mbed_official 76:652c2be531c7 42 _event_queue.dispatch_forever();
mbed_official 3:41f6be68aefb 43 }
mbed_official 3:41f6be68aefb 44
mbed_official 76:652c2be531c7 45 private:
mbed_official 76:652c2be531c7 46 /**
mbed_official 76:652c2be531c7 47 * iBeacon payload builder.
mbed_official 76:652c2be531c7 48 *
mbed_official 76:652c2be531c7 49 * This data structure contains the payload of an iBeacon. The payload is
mbed_official 76:652c2be531c7 50 * built at construction time and application code can set up an iBeacon by
mbed_official 76:652c2be531c7 51 * injecting the raw field into the GAP advertising payload as a
mbed_official 76:652c2be531c7 52 * GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA.
mbed_official 76:652c2be531c7 53 */
mbed_official 76:652c2be531c7 54 union Payload {
mbed_official 76:652c2be531c7 55 /**
mbed_official 76:652c2be531c7 56 * Raw data of the payload.
mbed_official 76:652c2be531c7 57 */
mbed_official 76:652c2be531c7 58 uint8_t raw[25];
mbed_official 76:652c2be531c7 59 struct {
mbed_official 76:652c2be531c7 60 /**
mbed_official 76:652c2be531c7 61 * Beacon manufacturer identifier.
mbed_official 76:652c2be531c7 62 */
mbed_official 76:652c2be531c7 63 uint16_t companyID;
mbed_official 76:652c2be531c7 64
mbed_official 76:652c2be531c7 65 /**
mbed_official 76:652c2be531c7 66 * Packet ID; Equal to 2 for an iBeacon.
mbed_official 76:652c2be531c7 67 */
mbed_official 76:652c2be531c7 68 uint8_t ID;
mbed_official 76:652c2be531c7 69
mbed_official 76:652c2be531c7 70 /**
mbed_official 76:652c2be531c7 71 * Length of the remaining data presents in the payload.
mbed_official 76:652c2be531c7 72 */
mbed_official 76:652c2be531c7 73 uint8_t len;
mbed_official 76:652c2be531c7 74
mbed_official 76:652c2be531c7 75 /**
mbed_official 76:652c2be531c7 76 * Beacon UUID.
mbed_official 76:652c2be531c7 77 */
mbed_official 76:652c2be531c7 78 uint8_t proximityUUID[16];
mbed_official 76:652c2be531c7 79
mbed_official 76:652c2be531c7 80 /**
mbed_official 76:652c2be531c7 81 * Beacon Major group ID.
mbed_official 76:652c2be531c7 82 */
mbed_official 76:652c2be531c7 83 uint16_t majorNumber;
mbed_official 76:652c2be531c7 84
mbed_official 76:652c2be531c7 85 /**
mbed_official 76:652c2be531c7 86 * Beacon minor ID.
mbed_official 76:652c2be531c7 87 */
mbed_official 76:652c2be531c7 88 uint16_t minorNumber;
mbed_official 76:652c2be531c7 89
mbed_official 76:652c2be531c7 90 /**
mbed_official 76:652c2be531c7 91 * Tx power received at 1 meter; in dBm.
mbed_official 76:652c2be531c7 92 */
mbed_official 76:652c2be531c7 93 uint8_t txPower;
mbed_official 76:652c2be531c7 94 };
mbed_official 76:652c2be531c7 95
mbed_official 76:652c2be531c7 96 /**
mbed_official 76:652c2be531c7 97 * Assemble an iBeacon payload.
mbed_official 76:652c2be531c7 98 *
mbed_official 76:652c2be531c7 99 * @param[in] uuid Beacon network ID. iBeacon operators use this value
mbed_official 76:652c2be531c7 100 * to group their iBeacons into a single network, a single region and
mbed_official 76:652c2be531c7 101 * identify their organization among others.
mbed_official 76:652c2be531c7 102 *
mbed_official 76:652c2be531c7 103 * @param[in] majNum Beacon major group ID. iBeacon exploitants may use
mbed_official 76:652c2be531c7 104 * this field to divide the region into subregions, their network into
mbed_official 76:652c2be531c7 105 * subnetworks.
mbed_official 76:652c2be531c7 106 *
mbed_official 76:652c2be531c7 107 * @param[in] minNum Identifier of the Beacon in its subregion.
mbed_official 76:652c2be531c7 108 *
mbed_official 76:652c2be531c7 109 * @param[in] transmitPower Measured transmit power of the beacon at 1
mbed_official 76:652c2be531c7 110 * meter. Scanners use this parameter to approximate the distance
mbed_official 76:652c2be531c7 111 * to the beacon.
mbed_official 76:652c2be531c7 112 *
mbed_official 76:652c2be531c7 113 * @param[in] companyIDIn ID of the beacon manufacturer.
mbed_official 76:652c2be531c7 114 */
mbed_official 76:652c2be531c7 115 Payload(
mbed_official 76:652c2be531c7 116 const uint8_t *uuid,
mbed_official 76:652c2be531c7 117 uint16_t majNum,
mbed_official 76:652c2be531c7 118 uint16_t minNum,
mbed_official 76:652c2be531c7 119 uint8_t transmitPower,
mbed_official 76:652c2be531c7 120 uint16_t companyIDIn
mbed_official 76:652c2be531c7 121 ) : companyID(companyIDIn),
mbed_official 76:652c2be531c7 122 ID(0x02),
mbed_official 76:652c2be531c7 123 len(0x15),
mbed_official 76:652c2be531c7 124 majorNumber(__REV16(majNum)),
mbed_official 76:652c2be531c7 125 minorNumber(__REV16(minNum)),
mbed_official 76:652c2be531c7 126 txPower(transmitPower)
mbed_official 76:652c2be531c7 127 {
mbed_official 76:652c2be531c7 128 memcpy(proximityUUID, uuid, 16);
mbed_official 76:652c2be531c7 129 }
mbed_official 76:652c2be531c7 130 };
mbed_official 76:652c2be531c7 131
mbed_official 76:652c2be531c7 132 /** Callback triggered when the ble initialization process has finished */
mbed_official 76:652c2be531c7 133 void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
mbed_official 76:652c2be531c7 134 if (params->error != BLE_ERROR_NONE) {
mbed_official 76:652c2be531c7 135 printf("Ble initialization failed.");
mbed_official 76:652c2be531c7 136 return;
mbed_official 76:652c2be531c7 137 }
mbed_official 76:652c2be531c7 138
mbed_official 76:652c2be531c7 139 print_mac_address();
mbed_official 76:652c2be531c7 140
mbed_official 76:652c2be531c7 141 start_advertising();
mbed_official 3:41f6be68aefb 142 }
mbed_official 3:41f6be68aefb 143
mbed_official 76:652c2be531c7 144 void start_advertising() {
mbed_official 76:652c2be531c7 145 /* Create advertising parameters and payload */
mbed_official 76:652c2be531c7 146
mbed_official 76:652c2be531c7 147 ble::AdvertisingParameters adv_parameters(
mbed_official 76:652c2be531c7 148 ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
mbed_official 76:652c2be531c7 149 ble::adv_interval_t(ble::millisecond_t(1000))
mbed_official 76:652c2be531c7 150 );
mbed_official 76:652c2be531c7 151
mbed_official 76:652c2be531c7 152 _adv_data_builder.setFlags();
mbed_official 76:652c2be531c7 153
mbed_official 76:652c2be531c7 154 /**
mbed_official 76:652c2be531c7 155 * The Beacon payload has the following composition:
mbed_official 76:652c2be531c7 156 * 128-Bit / 16byte UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
mbed_official 76:652c2be531c7 157 * Major/Minor = 0x1122 / 0x3344
mbed_official 76:652c2be531c7 158 * Tx Power = 0xC8 = 200, 2's compliment is 256-200 = (-56dB)
mbed_official 76:652c2be531c7 159 *
mbed_official 76:652c2be531c7 160 * Note: please remember to calibrate your beacons TX Power for more accurate results.
mbed_official 76:652c2be531c7 161 */
mbed_official 76:652c2be531c7 162 static const uint8_t uuid[] = { 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4,
mbed_official 76:652c2be531c7 163 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61 };
mbed_official 76:652c2be531c7 164 uint16_t major_number = 1122;
mbed_official 76:652c2be531c7 165 uint16_t minor_number = 3344;
mbed_official 76:652c2be531c7 166 uint16_t tx_power = 0xC8;
mbed_official 76:652c2be531c7 167 uint16_t comp_id = 0x004C;
mbed_official 76:652c2be531c7 168
mbed_official 76:652c2be531c7 169 Payload ibeacon(uuid, major_number, minor_number, tx_power, comp_id);
mbed_official 76:652c2be531c7 170
mbed_official 76:652c2be531c7 171 _adv_data_builder.setManufacturerSpecificData(ibeacon.raw);
mbed_official 76:652c2be531c7 172
mbed_official 76:652c2be531c7 173 /* Setup advertising */
mbed_official 76:652c2be531c7 174
mbed_official 76:652c2be531c7 175 ble_error_t error = _ble.gap().setAdvertisingParameters(
mbed_official 76:652c2be531c7 176 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 76:652c2be531c7 177 adv_parameters
mbed_official 76:652c2be531c7 178 );
mbed_official 3:41f6be68aefb 179
mbed_official 76:652c2be531c7 180 if (error) {
mbed_official 76:652c2be531c7 181 print_error(error, "_ble.gap().setAdvertisingParameters() failed");
mbed_official 76:652c2be531c7 182 return;
mbed_official 76:652c2be531c7 183 }
mbed_official 76:652c2be531c7 184
mbed_official 76:652c2be531c7 185 error = _ble.gap().setAdvertisingPayload(
mbed_official 76:652c2be531c7 186 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 76:652c2be531c7 187 _adv_data_builder.getAdvertisingData()
mbed_official 76:652c2be531c7 188 );
mbed_official 76:652c2be531c7 189
mbed_official 76:652c2be531c7 190 if (error) {
mbed_official 76:652c2be531c7 191 print_error(error, "_ble.gap().setAdvertisingPayload() failed");
mbed_official 76:652c2be531c7 192 return;
mbed_official 76:652c2be531c7 193 }
mbed_official 76:652c2be531c7 194
mbed_official 76:652c2be531c7 195 /* Start advertising */
mbed_official 76:652c2be531c7 196
mbed_official 76:652c2be531c7 197 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 45:0d307fc39fd0 198
mbed_official 76:652c2be531c7 199 if (error) {
mbed_official 76:652c2be531c7 200 print_error(error, "_ble.gap().startAdvertising() failed");
mbed_official 76:652c2be531c7 201 return;
mbed_official 76:652c2be531c7 202 }
mbed_official 76:652c2be531c7 203 }
mbed_official 76:652c2be531c7 204
mbed_official 76:652c2be531c7 205 private:
mbed_official 76:652c2be531c7 206 /* Event handler */
mbed_official 3:41f6be68aefb 207
mbed_official 76:652c2be531c7 208 void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
mbed_official 76:652c2be531c7 209 _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 76:652c2be531c7 210 }
mbed_official 76:652c2be531c7 211
mbed_official 76:652c2be531c7 212 private:
mbed_official 76:652c2be531c7 213 BLE &_ble;
mbed_official 76:652c2be531c7 214 events::EventQueue &_event_queue;
mbed_official 76:652c2be531c7 215
mbed_official 76:652c2be531c7 216 uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
mbed_official 76:652c2be531c7 217 ble::AdvertisingDataBuilder _adv_data_builder;
mbed_official 76:652c2be531c7 218 };
mbed_official 76:652c2be531c7 219
mbed_official 76:652c2be531c7 220 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 76:652c2be531c7 221 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 76:652c2be531c7 222 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
mbed_official 3:41f6be68aefb 223 }
mbed_official 3:41f6be68aefb 224
mbed_official 3:41f6be68aefb 225 int main()
mbed_official 3:41f6be68aefb 226 {
mbed_official 3:41f6be68aefb 227 BLE &ble = BLE::Instance();
mbed_official 76:652c2be531c7 228 ble.onEventsToProcess(schedule_ble_events);
mbed_official 3:41f6be68aefb 229
mbed_official 76:652c2be531c7 230 BeaconDemo demo(ble, event_queue);
mbed_official 76:652c2be531c7 231 demo.start();
mbed_official 3:41f6be68aefb 232
mbed_official 3:41f6be68aefb 233 return 0;
mbed_official 3:41f6be68aefb 234 }