Beacon demo for the BLE API using the nRF51822 native mode drivers

Dependencies:   BLE_API mbed nRF51822 X_NUCLEO_IDB0XA1

Introduction

Bluetooth Low Energy Beacons are a service that allow for highly localized positioning. The Beacon service is particularly useful for indoor positioning, low power positioning and location aware software. A particular use of the Beacon service is iBeacon. The iBeacon standard is a Apple specific implementation of Beacons.

The Basics

The Beacon service is a BLE Service that operates in advertising mode only. A Beacon service advertises 4 things:

  • A company ID
  • A unique UUID (unique to a retailer)
  • A Major number (ex a store number)
  • A Minor number (ex a location in the store)
  • Signal Strength at transmitter (requires calibration per each device)

These pieces of information are all you need for a Beacon service to work. The majority of the heavy lifting is done by the smart phone application that reads these four fields and then uses a web app or a database of some sort to turn these numbers into valuable information about what you are near and how near you are to it.

The signal strength field is compared to the actual signal strength at the receiver to determine how close the beacon is to the phone. The number used is the calibrated signal strength 1 meter from the device. By doing this 1 meter increments can be used to measure distance from the Beacon. The distances usually get broken down into 3 ranges:

  • Immediate: Within a few centimeters
  • Near: Within a couple of meters
  • Far: Greater than 10 meters away

Company ID's are used to make beacon UUID's unique to companies. Some example company UUID's are:

  • 0x004C - Apple Inc.
  • 0x0059 - Nordic Semiconductor
  • 0x0078 - Nike
  • ​0x015D - Estimote
  • ​0x0171 - Amazon Fulfillment Service
  • 0xFFFF - reserved for internal testing before release

Here is the Bluetooth SIG's full list of Company ID's.

Example : Coffee Shop X

For example, if a smartphone app reads a BLE Beacon with UUID = 0x1234546... , Major Number=5, Minor number = 3, it would check that against a database. From that database it would find out that UUID 0x123456... is owned by Coffee Shop X, that Major number 5 belongs to the store on main street and that Minor number 3 belongs to the coffee rack in that store. Then the application could check to see if there are any deals for the Coffee Shop X on Main Street on Coffee today. If there are any deals the phone could then alert the user and display a coupon code.

Example : museum

The Beacon service also provides a way for the phone to tell how close it is to the beacon. This can be useful for location aware applications, such as in a museum. For example, the smartphone reads a BLE Beacon with UUID = 0x98765....., Major Number=1, minor number = 0. The smartphone then looks this up in a database and find the UUID is for the Natural Science Museum, Major Number 1 = the Art Gallery room 1, and the minor number 0 = an abstract painting of a duck. If we assume all the paintings are spread out at 10feet each, then the application can sense when you are within 3 feet of the painting (based on signal strength of the Beacon) and give the user information about the painting they are approaching.

Technical Details

An iBeacon is just a normal Bluetooth LE device broadcasting advertisements with special data shoved into the Manufacturer Specific Data field.

The iBeacon prefix is little more than metadata about the advertisement packet.

BytesDatadescription
0,1,20x020106This sets the flags for General Discoverable and BR/EDR not supported
3,40x1AFFThis says the length of the Manufacturer specific data field will be 26 bytes
0,10x4C00Company ID
20x02ID
30x15length of remaining data in bytes (16B UUID+ 2B major, 2B minor, 1B Txpower)

Note that bytes 0-4 are set implicitly by the API by declaring the advertising data to be LE General Discoverable and BR/EDR not supported. The remaining fields that make up an iBeacon advertisement packet can be clearly seen in the image below.

http://www.havlena.net/wp-content/uploads/ibeacon-packet.png

For a more depth explanation please see these well done explanations:

Committer:
rohit.grover
Date:
Tue May 20 18:04:33 2014 +0100
Revision:
7:e2bfd5db6713
Parent:
6:26eab6ee6df4
Child:
8:d851d92601b7
better documentation to explain the structure of the beacon advertising payload

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ktownsend 0:7613d21e5974 1 /* mbed Microcontroller Library
ktownsend 0:7613d21e5974 2 * Copyright (c) 2006-2013 ARM Limited
ktownsend 0:7613d21e5974 3 *
ktownsend 0:7613d21e5974 4 * Licensed under the Apache License, Version 2.0 (the "License");
ktownsend 0:7613d21e5974 5 * you may not use this file except in compliance with the License.
ktownsend 0:7613d21e5974 6 * You may obtain a copy of the License at
ktownsend 0:7613d21e5974 7 *
ktownsend 0:7613d21e5974 8 * http://www.apache.org/licenses/LICENSE-2.0
ktownsend 0:7613d21e5974 9 *
ktownsend 0:7613d21e5974 10 * Unless required by applicable law or agreed to in writing, software
ktownsend 0:7613d21e5974 11 * distributed under the License is distributed on an "AS IS" BASIS,
ktownsend 0:7613d21e5974 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ktownsend 0:7613d21e5974 13 * See the License for the specific language governing permissions and
ktownsend 0:7613d21e5974 14 * limitations under the License.
ktownsend 0:7613d21e5974 15 */
ktownsend 0:7613d21e5974 16
ktownsend 0:7613d21e5974 17 #include "mbed.h"
ktownsend 0:7613d21e5974 18 #include "nRF51822n.h"
ktownsend 0:7613d21e5974 19
ktownsend 0:7613d21e5974 20 nRF51822n nrf; /* BLE radio driver */
ktownsend 0:7613d21e5974 21
ktownsend 0:7613d21e5974 22 DigitalOut led1(LED1);
ktownsend 0:7613d21e5974 23 DigitalOut led2(LED2);
ktownsend 0:7613d21e5974 24 Ticker flipper;
ktownsend 0:7613d21e5974 25 Serial pc(USBTX,USBRX);
ktownsend 0:7613d21e5974 26
ktownsend 0:7613d21e5974 27 void tickerCallback(void);
ktownsend 0:7613d21e5974 28
ktownsend 0:7613d21e5974 29 /**************************************************************************/
ktownsend 0:7613d21e5974 30 /*!
ktownsend 0:7613d21e5974 31 @brief Program entry point
ktownsend 0:7613d21e5974 32 */
ktownsend 0:7613d21e5974 33 /**************************************************************************/
ktownsend 0:7613d21e5974 34 int main(void)
ktownsend 0:7613d21e5974 35 {
ktownsend 0:7613d21e5974 36 *(uint32_t *)0x40000504 = 0xC007FFDF;
ktownsend 0:7613d21e5974 37 *(uint32_t *)0x40006C18 = 0x00008000;
ktownsend 0:7613d21e5974 38
ktownsend 0:7613d21e5974 39 /* Setup blinky: led1 is toggled in main, led2 is toggled via Ticker */
rohit.grover 6:26eab6ee6df4 40 led1 = 1;
rohit.grover 6:26eab6ee6df4 41 led2 = 1;
ktownsend 0:7613d21e5974 42 flipper.attach(&tickerCallback, 1.0);
ktownsend 0:7613d21e5974 43
ktownsend 0:7613d21e5974 44 /* Initialise the nRF51822 */
ktownsend 0:7613d21e5974 45 pc.printf("Initialising the nRF51822\n\r");
ktownsend 0:7613d21e5974 46 nrf.init();
rohit.grover 6:26eab6ee6df4 47
rohit.grover 5:97ce285ff00a 48 GapAdvertisingParams advParams (
rohit.grover 5:97ce285ff00a 49 GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED );
ktownsend 0:7613d21e5974 50 GapAdvertisingData advData;
ktownsend 0:7613d21e5974 51 GapAdvertisingData scanResponse;
ktownsend 0:7613d21e5974 52
rohit.grover 7:e2bfd5db6713 53 /*
rohit.grover 7:e2bfd5db6713 54 * For this demo application, populate the beacon advertisement payload
rohit.grover 7:e2bfd5db6713 55 * with 2 AD structures: FLAG and MSD
rohit.grover 7:e2bfd5db6713 56 *
rohit.grover 7:e2bfd5db6713 57 * Reference:
rohit.grover 7:e2bfd5db6713 58 * Bluetooth Core Specification 4.0 (Vol. 3), Part C, Section 11, 18
rohit.grover 7:e2bfd5db6713 59 */
rohit.grover 7:e2bfd5db6713 60
rohit.grover 7:e2bfd5db6713 61 /* Define an Beacon payload.
rohit.grover 7:e2bfd5db6713 62
rohit.grover 7:e2bfd5db6713 63 This is the data part of the MSD AdvertisingData structure to be added to
rohit.grover 7:e2bfd5db6713 64 the advertising payload.
ktownsend 0:7613d21e5974 65 --------------------------------------------------------------
ktownsend 0:7613d21e5974 66 128-Bit UUID = E2 0A 39 F4 73 F5 4B C4 A1 2F 17 D1 AD 07 A9 61
ktownsend 0:7613d21e5974 67 Major/Minor = 0000 / 0000
ktownsend 0:7613d21e5974 68 Tx Power = C8
ktownsend 0:7613d21e5974 69 */
rohit.grover 7:e2bfd5db6713 70 uint8_t beaconPayload[] = {
rohit.grover 7:e2bfd5db6713 71 0x4C, 0x00, // Company identifier code (0x004C == Apple)
rohit.grover 7:e2bfd5db6713 72 0x02, // ID
rohit.grover 7:e2bfd5db6713 73 0x15, // length of the remaining payload
rohit.grover 7:e2bfd5db6713 74 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, // UUID
rohit.grover 7:e2bfd5db6713 75 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61,
rohit.grover 7:e2bfd5db6713 76 0x00, 0x00, // the major value to differenciate a location
rohit.grover 7:e2bfd5db6713 77 0x00, 0x00, // the minor value to differenciate a location
rohit.grover 7:e2bfd5db6713 78 0xC8 // 2's complement of the Tx power (-56dB)
rohit.grover 7:e2bfd5db6713 79 };
ktownsend 0:7613d21e5974 80
ktownsend 0:7613d21e5974 81 /* Make sure we get a clean start */
ktownsend 0:7613d21e5974 82 nrf.reset();
ktownsend 0:7613d21e5974 83
ktownsend 0:7613d21e5974 84 advData.addFlags(GapAdvertisingData::BREDR_NOT_SUPPORTED);
rohit.grover 5:97ce285ff00a 85 advData.addData(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA,
rohit.grover 5:97ce285ff00a 86 beaconPayload,
rohit.grover 5:97ce285ff00a 87 sizeof(beaconPayload));
ktownsend 0:7613d21e5974 88
ktownsend 0:7613d21e5974 89 /* Start advertising! */
ktownsend 0:7613d21e5974 90 nrf.getGap().setAdvertisingData(advData, scanResponse);
ktownsend 0:7613d21e5974 91 nrf.getGap().startAdvertising(advParams);
ktownsend 0:7613d21e5974 92
ktownsend 0:7613d21e5974 93 /* Do blinky on LED1 while we're waiting for BLE events */
rohit.grover 5:97ce285ff00a 94 for (;; ) {
rohit.grover 6:26eab6ee6df4 95 led1 = !led1;
rohit.grover 6:26eab6ee6df4 96 wait(1);
ktownsend 0:7613d21e5974 97 }
ktownsend 0:7613d21e5974 98 }
ktownsend 0:7613d21e5974 99
ktownsend 0:7613d21e5974 100 /**************************************************************************/
ktownsend 0:7613d21e5974 101 /*!
ktownsend 0:7613d21e5974 102 @brief Ticker callback to switch led2 state
ktownsend 0:7613d21e5974 103 */
ktownsend 0:7613d21e5974 104 /**************************************************************************/
ktownsend 0:7613d21e5974 105 void tickerCallback(void)
ktownsend 0:7613d21e5974 106 {
ktownsend 0:7613d21e5974 107 led2 = !led2;
ktownsend 0:7613d21e5974 108 }