Introduction

As a continuation of our series on Bluetooth beacons (part 1 here and part 2 here), today we cover Apple’s iBeacon standard in a bit more detail.

iBeacon is especially useful for deploying location-awareness applications and monitoring user behavior within an area. It was introduced in iOS 7 and utilizes Bluetooth Low Energy (BLE) to send out advertisements that get discovered and utilized by other BLE-capable devices (especially smartphones).

It’s an application layer implementation on top of BLE, so it requires awareness on both sides:

  • Implementing the iBeacon format on a BLE device (normally battery-operated)
  • Implementing awareness of the iBeacon format on another device capable of acting as a BLE scanner (normally a smartphone app)

The three main parts in an iBeacon advertising packet:

  • UUID (16 bytes): specific to the app (e.g. one per manufacturer)
  • Major (2 bytes): defines sub-region with UUID
  • Minor (2 bytes): defines a smaller region within Major area

Here’s an example showing how this can be implemented in the field. The example is for a chain of international stores.

  • UUID is common across all stores and defined in the app.
  • Major identifier is assigned to each of the different store locations.
  • Minor identifiers are assigned for regions within the stores
  • UUID, Major, and Minor identifiers are not registered with Apple and are chosen at the developer/manufacturer discretion.

Keep in mind that iBeacon is not exclusive to iOS applications and can be implemented in any BLE scanner/app, including in Android applications and on devices such as a Raspberry Pi. All the app needs is awareness of the iBeacon BLE advertisement format, and Apple simply defined the format.

Here are some examples of how iBeacon can be utilized for location-based actions, specifically on iOS:

  • If the mobile app defines only the UUID, then the app can detect whenever a user enters any of the stores (with the condition that the user has the app installed and has given it the appropriate permissions).
  • If the mobile app registers a UUID + Major, then the app can detect whenever a user enters a specific store (with the condition that the user has the app installed and has given it the appropriate permissions).
  • If the mobile app registers a UUID + Major + Minor, then the app can detect whenever a user enters a specific region within a specific user (with the condition that the user has the app installed and given the appropriate permissions).
  • In all of the above cases, the app will also get notified when a user exits the defined region (any store, a specific store, or a region with a specific store).

These operations are referred to as “region monitoring”. In each case, the app may be implemented in a way such that the user is presented with relevant information to the region entered/exited.

iOS also supports the concept of “ranging”. This refers to the operation of estimating proximity to a beacon.

Apple details a calibration process that can be used to make the ranging more accurate. This involves measuring the RSSI of the advertising beacon at a constant distance of 1 meter at multiple positions, then applying the average measured RSSI value to the beacon’s transmit power. This is particularly useful during the deployment phase of the beacons.

One misconception about beacons is that they can track users. The beacon devices themselves only transmit packets and do not generally accept connections and incoming packets from a mobile device. This means that only the app can detect the user’s location and not the beacons themselves.

Having said that, though, if an app reports the region a user enters to a cloud server or records these locations locally, then a user’s privacy may be compromised. In the end, apps are generally required to disclose this collection of user data from the user.

Implementing iBeacon on nRF52 devices

To learn more about how to implement iBeacon devices, we’ll be using an example provided within the nRF5 SDK (version 16.0.0 in our case).

The different hardware and software requirements are:

  • Segger Embedded Studio (SES)
  • nRF5 SDK version 16.0.0 or later
  • An nRF52 development board (I’m using the nRF52840 DK)
  • nRF command-line tools
  • A development PC for developing and flashing the development board
  • A mobile phone running a BLE scanner app such as LightBlue or nRF Connect

The example we’ll be using is located at <nRF5 SDK Folder>/examples/ble_peripheral/ble_app_beacon/. The example by default implements the following:

  • iBeacon device
  • Beacon UUID: 01122334-4556-6778-899A-ABBCCDDEEFF0
  • Major: 0x0102
  • Minor: 0x0304
  • Advertising Interval: 100 msec
  • Company Identifier: 0x0059 (Nordic Semiconductor)
  • Beacon’s measured RSSI at a 1-meter distance in dBm: 0xC3
  • Device Type: 0x02 (Beacon device)
  • Total advertisement size: 0x17 == 23 bytes (which is the maximum advertisement packet size in BLE including the length value (2 bytes))

Notice that the device name is not included in the advertisement data. In this implementation, this is not necessary and would not possible since the advertisement data is already at maximum size.

Note: the example also implements an option for setting the Major and Minor values in the UICR (User information configuration registers) section. These registers are non-volatile memory (NVM) registers for configuring user-specific settings. This is especially helpful in cases where you need to program multiple devices with specific Major and Minor values without having to reprogram the devices each time those values are changed. Consider using this method for cases where you need to assign a number of beacons with specific Major and Minor values in preparation for deployment in the field.
For more information on the UICR section: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fuicr.html&cp=4_0_0_3_4

Of the parameters listed above that you will likely be interested in modifying the following to match your application needs:

  • Advertising Interval
  • UUID value
  • Major value
  • Minor value
  • Company Identifier (to match your own Bluetooth assigned Company Identifier
  • Measured RSSI (depending on your own measurements for your hardware)

iBeacon Implementation and Source Code

Let’s take a look at the different parts of the example source and better understand how the iBeacon example is implemented. We’ll take a look at only the parts of the code which interest us the most.

The source code file we’re interested in is main.c.

main.c

Setting the Advertising Interval:

Setting the total iBeacon advertisement data length (including length value):

Setting the advertisement data/payload length:

Setting the device type valute (beacon device type = 0x02):

The beacon measured RSSI value (at 1 meter, and in dBm):

The Nordic Semiconductor company identifier:

The Major value:

The Minor value:

The beacon UUID:

Defining the beacon info (based on the values defined above):

The  advertising_init()  function:

The advertising_start() function:

The main() function:

Let’s open the beacon example from the nRF5 SDK folder and compile it. To open this project, you can simply double click the file located at <nRF5 SDK Folder>/examples/ble_peripheral/ble_app_beacon/pca10056/s140/ses/ble_app_beacon_pca10056_s140.emProject:

Location of SES Project file
Building Example
Build complete

Once we’ve compiled the example successfully, we can flash it to our development board (but first make sure it is connected to your development PC). You can do so by navigating to the Target file menu, clicking “Connect J-Link“, then “Download ble_app_beacon_pca10056_s140“:

Flashing the development board

Once you have the example flashed and running on the board, you should see LED 1 on the board start flashing:

LED 1 flashing

Now, you can open a BLE scanner app such as nRF Connect (for iOS or Android or Desktop) and you’ll be able to see the beacon and the advertising data.
Note: you can ignore the device name displayed as our device does not set a device name, and if a previously cached device name may be shown by the app.

As you can see, the app recognized and parsed all the advertisement data for us in a friendly readable format. Keep in mind that the app displays the Major and Minor values in decimal whereas we set them in hex format (Major = 0x0102 == 258, Minor = 0x0304 == 772).

Let’s go ahead and change some of the parameters to see if the changes get reflected in the app. We’ll go ahead and make the following changes:

  • Change Major from 0x0102 to 0x1122 == 4386
  • Change Minor version from 0x0304 to 0x3344 == 13124

In source code (main.c):

Compile the application and re-flash it to the device. Once you’ve done so, rescan for BLE devices in the mobile app (I’m using nRF Connect for iOS here):

As you can see, the Major and Minor have been updated and match what we expected.

Flashing the Major and Minor values to UICR section

NOTE: As we mentioned previously, this method is very useful in cases where you want to modify the Major and Minor values for multiple devices (or the same device) without having to reprogram the device. This is especially useful in preparing a large number of beacons for deployment in the field.

As a final exercise, let’s try modifying the Major and Minor values by writing them to the UICR section. This method required the use of the nrfjprog command-line tool.

But first, we need to enable this functionality in the code (just once).

Look for the function advertising_init()and right above it, define the following macros:

#define USE_UICR_FOR_MAJ_MIN_VALUES
#define UICR_ADDRESS 0x10001080
#define MAJ_VAL_OFFSET_IN_BEACON_INFO 0x12

The address defined above is the first available “customer” address per the Nordic documentation (https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fuicr.html&cp=4_0_0_3_4).

The MAJ_VAL_OFFSET_IN_BEACON_INFO value is the offset of the Major value within the m_beacon_info data structure.

This will enable the following code section in advertising_init():

Once you compile and flash the updated application to your development board, you should see the Major and Minor values both equal 65535 (if you have previously not written to the UICR address specified above). This is because the application now reads the values from UICR instead of from the source code.

Now, let’s update the values by writing new ones (Major = 0x0001 and Minor = 0x0002) to the UICR address we defined (via nrfjprog).

To do this, run the following command from a command-line terminal/shell prompt:

nrfjprog --memwr 0x10001080 --val 0x00010002

In this case, we didn’t specify the serial number of the Segger chip since we made sure we only had one development board connected. If you have multiple devices connected to your development PC, then you’d have to specify the serial number.

All we need now is to reset the development board and perform a new scan in the BLE scanner app:

As you can see, Major = 1 and Minor = 2, which matches what we set them as.

NOTE: You will have to erase the UICR area before writing again to update the values. You can learn more about how to do so here: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf5x_cltools%2FUG%2Fcltools%2Fnrf5x_nrfjprogexe_reference.html

Summary & Closing

In this tutorial, we covered Apple’s iBeacon standard in a bit more detail than in the previous two tutorials on beacons (part 1 & part 2).

We took a look at the details of the iBeacon advertising packet format, covered different use cases for different scenarios, and went over implementing an iBeacon example on the nRF52 platform.

In a future post, we will cover the Eddystone standard in a similar fashion.

Take your BLE knowledge to the next level

If you’re interested in staying up-to-date on the latest developments in BLE including an upcoming complete course on Beacon Development, then check out the Bluetooth Developer Academy.

By joining the Bluetooth Developer Academy, you will get access to a growing library of courses and tutorials.

Here’s what one Academy member has to say:

If you’re developing a BLE project, you need two things, a good BLE sniffer and the Bluetooth Developer Academy. I am very happy to be part of this community and look forward to what comes next.

– Christopher Gates, Principal System Security Architect – Velentium

The current courses include:

  • The Basics of Bluetooth Low Energy
  • Analysis of BLE events using a BLE sniffer
  • Long-range mode (Coded PHY) using Bluetooth 5.0
  • Developing nRF52 applications using Visual Studio Code
  • Over the Air Device Firmware Update (OTA DFU) – nRF52 use case
  • Getting Started with Zephyr (including adding custom GATT Services and Characteristics)
  • The Developer’s Guide to what’s new in Bluetooth 5.2
  • SweynTooth: A Summary for BLE Developers
  • Introduction to BLE Security
  • Getting Started with BlueZ development
  • Introduction to BLE Development for iOS
  • …and more courses added each month!

For a full list of courses included, check out the Courses Library here:

Bluetooth Developer Academy Courses Library

The Academy also features a thriving community of Bluetooth experts, developers, and innovators. You’ll get to connect and interact with other experts in the Bluetooth space, learn from others’ experience and knowledge, and share yours.

Also included in the Academy is access to private support from me personally.

In the community, you will find:

  • Discussions around new features such as long-range mode (Bluetooth 5.0) and direction-finding (Bluetooth 5.1).
  • Discussions around the capabilities of different BLE sniffers.
  • Comparisons of BLE support and restrictions in iOS and Android.
  • Various technical questions and answers to these questions.
  • Listing of Bluetooth-related job openings.
  • And many more discussions!

Learn More About the Bluetooth Developer Academy