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

Committer:
YJKIYOKAWA
Date:
Thu Mar 19 00:25:22 2020 +0000
Revision:
82:7f3513808f75
Parent:
76:652c2be531c7
Child:
83:d0596095a535
delta beacon

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(
YJKIYOKAWA 82:7f3513808f75 148 ble::advertising_type_t::NON_CONNECTABLE_UNDIRECTED ,
YJKIYOKAWA 82:7f3513808f75 149 ble::adv_interval_t(ble::millisecond_t(100))
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 */
YJKIYOKAWA 82:7f3513808f75 162 static const uint8_t uuid[] = { 0x74, 0x27, 0x8B, 0xDA, 0xB6, 0x44, 0x45, 0x20,
YJKIYOKAWA 82:7f3513808f75 163 0x8F, 0x0C, 0x72, 0x0E, 0xAF, 0x05, 0x99, 0x35 };
YJKIYOKAWA 82:7f3513808f75 164 uint16_t major_number = 1;
YJKIYOKAWA 82:7f3513808f75 165 uint16_t minor_number = 3;
mbed_official 76:652c2be531c7 166 uint16_t tx_power = 0xC8;
YJKIYOKAWA 82:7f3513808f75 167 uint16_t comp_id = 0x069e;
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 }