The Uniform Resource Identifier Beacon (UriBeacon) defines Bluetooth 4.0 Advertisement Data that contain Web URIs. URIBeacon provides a way for Bluetooth Low Energy devices to discover nearby URIs, for example, provides a way for a user to discover a short URL and then download it on their smartphone.

Dependencies:   BLE_API mbed nRF51822

Fork of BLE_PhysicalWeb by Bluetooth Low Energy

This example demonstrates how to set up and initialize a basic URI Beacon. For a more advanced example of using a URI beacon please see the BLE_PhysicalWeb project. The Google Github Page also gives a great description of what UriBeacons are and how to use them.

Basic Details

URI Beacons are a standard way of providing a URI link in a BLE advertising packet. Website URL's are the most popular URI's. The goal of URI Beacons are to act as a bridge between the physical and digital worlds. Since the URI can be any web capable link the possibilities for use are really endless. The UriBeacons can be thought of as a natural extension of and more useful version of QR codes.

Smartphone App Links

iPhone Physical Web app

Android App

Walkthrough of Physical Web application

Size of URI

The UriBeacon has one purpose, to advertise a web link. Because of the nature of BLE these web links have to be small. In order to provide a nice balance of small and useful the UriBeacon specification has abstracted out the representation of the URI prefix('http://www.', 'https://www.' , ...etc) and suffix ('.com','.org','.edu','.gov' ...etc) to a single byte each. Of the 27 bytes available for a usual BLE payload the UriBeacon has 19 bytes available for the URI. Of these 19bytes one byte must be given to the prefix. That leaves 18 bytes to fit the address and the suffix into. If the suffix used is not one of the standard ones in the UriBeacon specification then each letter will take up 1 byte instead of the entire suffix being abbreviated into a single byte.

Here are the acceptable abbreviations currently available

PreFixSuffix
http://www..com/
https://www..org/
http://.edu/
https://.net/
urn:uuid:.info/
.biz/
.gov/
.com
.org
.edu
.net
.info
.biz
.gov

So for example the address "http://www.google.com" would take up 8 bytes. Both "http://www." and ".com" are supported abbreviations so each will be shortened to 1 byte.

Number of BytesData
1"http://www." abbreviated
6"google", 1 byte for each letter
1".com/" abbreviated

An address like "http://www.bit.ly/xyz" would take up 11 bytes. Notice that ".ly" is not a supported suffix, so each letter takes up 1 byte.

Number of BytesData
1"http://www." abbreviated
10"bit.ly/xyz"

Even addresses with the suffix in the middle are abbreviated, ie "http://www.youtube.com/XYZ". Notice here that the '.com' is in the middle of an address, it is still shortened to just 1 byte.

Number of BytesData
1"http://www." abbreviated
7"youtube"
1".com/" abbreviated
4"XYZ"

Using UriBeacons with mbed BLE API

Using the UriBeacon with the mbed API is rather simple. Just like any other BLE project you must first initialize the BLE baselayer by creating a ble object.

Initialize_bl_object

BLEDevice ble;

Then you pass the BLE object to a UriBeacon config service.

Configure_UriBeacon_Service

URIBeaconConfigService *uriBeaconConfig;
uriBeaconConfig = new URIBeaconConfigService(ble, "http://www.mbed.org");

Optionally you can then adjust settings of the UriBeacon such as transmission power levels, grabbing verbose debug information and other handy dandy services.

Optional_UriBeacon_configuration

/* Adjust the TX Power Level */
    const int8_t powerLevels[] = {-20, -4, 0, 10};
    uriBeaconConfig->setTxPowerLevels(powerLevels); // Set TX power levels, Lowest(-20), Low(-4), Medium(0), High(10)
    uriBeaconConfig->setTxPowerMode(URIBeaconConfigService::TX_POWER_MODE_LOW); // Set transmission in Low power mode

/* Adjust Beacon Period*/
setBeaconPeriod(1000); // Set beacon to advertise every 1000ms

Other UriBeacon Services

This is just the bare basics of how URI beacons work. There is also a configuration service that allows URI beacons to be updated, locked, and provides other management feature. That is beyond the scope of this example but details can be found in the Technical Details section below.

Technical Details

For more details on how URI beacons work please see these websites:
UriBeacon Github Project : the github home for all things UriBeacon (maintained by google)
UriBeacon Specification : lots of good technical details
UriBeacon configuration service - This is a service that pairs with the UriBeacon that allows changing the URI's, locking them, and some other cool features. This service is not detailed in this example application.
Android App : smartphone application to view nearby UriBeacons.
iOS App : Sample code for using UriBeacons with iOS.
The PhysicalWeb Project : a project that the UriBeacon is central to.

In case you're really interested here is a diagram that nicely sums up how the 27bytes of advertising data payload are used. https://github.com/google/uribeacon/raw/master/specification/uribeacon-figure.png

Committer:
rgrover1
Date:
Thu Dec 10 07:42:47 2015 +0000
Revision:
29:5a1112254406
Parent:
17:e2c0a1696e39
updating underlying libraries to the latest. ; also fixed a bug in main() in the loop which waits for initialization to complete.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rgrover1 16:1daa78939a3b 1 /* mbed Microcontroller Library
rgrover1 16:1daa78939a3b 2 * Copyright (c) 2006-2015 ARM Limited
rgrover1 16:1daa78939a3b 3 *
rgrover1 16:1daa78939a3b 4 * Licensed under the Apache License, Version 2.0 (the "License");
rgrover1 16:1daa78939a3b 5 * you may not use this file except in compliance with the License.
rgrover1 16:1daa78939a3b 6 * You may obtain a copy of the License at
rgrover1 16:1daa78939a3b 7 *
rgrover1 16:1daa78939a3b 8 * http://www.apache.org/licenses/LICENSE-2.0
rgrover1 16:1daa78939a3b 9 *
rgrover1 16:1daa78939a3b 10 * Unless required by applicable law or agreed to in writing, software
rgrover1 16:1daa78939a3b 11 * distributed under the License is distributed on an "AS IS" BASIS,
rgrover1 16:1daa78939a3b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rgrover1 16:1daa78939a3b 13 * See the License for the specific language governing permissions and
rgrover1 16:1daa78939a3b 14 * limitations under the License.
rgrover1 16:1daa78939a3b 15 */
rgrover1 16:1daa78939a3b 16
rgrover1 29:5a1112254406 17 extern "C" {
rgrover1 16:1daa78939a3b 18 #include "pstorage.h"
rgrover1 29:5a1112254406 19 }
rgrover1 16:1daa78939a3b 20 #include "nrf_error.h"
rgrover1 16:1daa78939a3b 21 #include "ConfigParamsPersistence.h"
rgrover1 16:1daa78939a3b 22
rgrover1 17:e2c0a1696e39 23 /**
rgrover1 17:e2c0a1696e39 24 * Nordic specific structure used to store params persistently.
rgrover1 17:e2c0a1696e39 25 * It extends URIBeaconConfigService::Params_t with a persistence signature.
rgrover1 17:e2c0a1696e39 26 */
rgrover1 17:e2c0a1696e39 27 struct PersistentParams_t {
rgrover1 17:e2c0a1696e39 28 URIBeaconConfigService::Params_t params;
rgrover1 17:e2c0a1696e39 29 uint32_t persistenceSignature; /* This isn't really a parameter, but having the expected
rgrover1 17:e2c0a1696e39 30 * magic value in this field indicates persistence. */
rgrover1 17:e2c0a1696e39 31
rgrover1 17:e2c0a1696e39 32 static const uint32_t MAGIC = 0x1BEAC000; /* Magic that identifies persistence */
rgrover1 17:e2c0a1696e39 33 };
rgrover1 17:e2c0a1696e39 34
rgrover1 17:e2c0a1696e39 35 /**
rgrover1 17:e2c0a1696e39 36 * The following is a module-local variable to hold configuration parameters for
rgrover1 17:e2c0a1696e39 37 * short periods during flash access. This is necessary because the pstorage
rgrover1 17:e2c0a1696e39 38 * APIs don't copy in the memory provided as data source. The memory cannot be
rgrover1 17:e2c0a1696e39 39 * freed or reused by the application until this flash access is complete. The
rgrover1 17:e2c0a1696e39 40 * load and store operations in this module initialize persistentParams and then
rgrover1 17:e2c0a1696e39 41 * pass it on to the 'pstorage' APIs.
rgrover1 17:e2c0a1696e39 42 */
rgrover1 17:e2c0a1696e39 43 static PersistentParams_t persistentParams;
rgrover1 17:e2c0a1696e39 44
rgrover1 16:1daa78939a3b 45 static pstorage_handle_t pstorageHandle;
rgrover1 16:1daa78939a3b 46
rgrover1 17:e2c0a1696e39 47 /**
rgrover1 17:e2c0a1696e39 48 * Dummy callback handler needed by Nordic's pstorage module. This is called
rgrover1 17:e2c0a1696e39 49 * after every flash access.
rgrover1 17:e2c0a1696e39 50 */
rgrover1 16:1daa78939a3b 51 static void pstorageNotificationCallback(pstorage_handle_t *p_handle,
rgrover1 17:e2c0a1696e39 52 uint8_t op_code,
rgrover1 17:e2c0a1696e39 53 uint32_t result,
rgrover1 17:e2c0a1696e39 54 uint8_t *p_data,
rgrover1 17:e2c0a1696e39 55 uint32_t data_len)
rgrover1 16:1daa78939a3b 56 {
rgrover1 16:1daa78939a3b 57 /* APP_ERROR_CHECK(result); */
rgrover1 16:1daa78939a3b 58 }
rgrover1 16:1daa78939a3b 59
rgrover1 16:1daa78939a3b 60 /* Platform-specific implementation for persistence on the nRF5x. Based on the
rgrover1 16:1daa78939a3b 61 * pstorage module provided by the Nordic SDK. */
rgrover1 17:e2c0a1696e39 62 bool loadURIBeaconConfigParams(URIBeaconConfigService::Params_t *paramsP)
rgrover1 16:1daa78939a3b 63 {
rgrover1 17:e2c0a1696e39 64 static bool pstorageInitied = false;
rgrover1 17:e2c0a1696e39 65 if (!pstorageInitied) {
rgrover1 17:e2c0a1696e39 66 pstorage_init();
rgrover1 16:1daa78939a3b 67
rgrover1 17:e2c0a1696e39 68 static pstorage_module_param_t pstorageParams = {
rgrover1 17:e2c0a1696e39 69 .cb = pstorageNotificationCallback,
rgrover1 17:e2c0a1696e39 70 .block_size = sizeof(PersistentParams_t),
rgrover1 17:e2c0a1696e39 71 .block_count = 1
rgrover1 17:e2c0a1696e39 72 };
rgrover1 17:e2c0a1696e39 73 pstorage_register(&pstorageParams, &pstorageHandle);
rgrover1 17:e2c0a1696e39 74 pstorageInitied = true;
rgrover1 17:e2c0a1696e39 75 }
rgrover1 17:e2c0a1696e39 76
rgrover1 17:e2c0a1696e39 77 if ((pstorage_load(reinterpret_cast<uint8_t *>(&persistentParams), &pstorageHandle, sizeof(PersistentParams_t), 0) != NRF_SUCCESS) ||
rgrover1 17:e2c0a1696e39 78 (persistentParams.persistenceSignature != PersistentParams_t::MAGIC)) {
rgrover1 16:1daa78939a3b 79 // On failure zero out and let the service reset to defaults
rgrover1 16:1daa78939a3b 80 memset(paramsP, 0, sizeof(URIBeaconConfigService::Params_t));
rgrover1 17:e2c0a1696e39 81 return false;
rgrover1 16:1daa78939a3b 82 }
rgrover1 17:e2c0a1696e39 83
rgrover1 17:e2c0a1696e39 84 memcpy(paramsP, &persistentParams.params, sizeof(URIBeaconConfigService::Params_t));
rgrover1 17:e2c0a1696e39 85 return true;
rgrover1 16:1daa78939a3b 86 }
rgrover1 16:1daa78939a3b 87
rgrover1 16:1daa78939a3b 88 /* Platform-specific implementation for persistence on the nRF5x. Based on the
rgrover1 16:1daa78939a3b 89 * pstorage module provided by the Nordic SDK. */
rgrover1 17:e2c0a1696e39 90 void saveURIBeaconConfigParams(const URIBeaconConfigService::Params_t *paramsP)
rgrover1 16:1daa78939a3b 91 {
rgrover1 17:e2c0a1696e39 92 memcpy(&persistentParams.params, paramsP, sizeof(URIBeaconConfigService::Params_t));
rgrover1 17:e2c0a1696e39 93 if (persistentParams.persistenceSignature != PersistentParams_t::MAGIC) {
rgrover1 17:e2c0a1696e39 94 persistentParams.persistenceSignature = PersistentParams_t::MAGIC;
rgrover1 16:1daa78939a3b 95 pstorage_store(&pstorageHandle,
rgrover1 17:e2c0a1696e39 96 reinterpret_cast<uint8_t *>(&persistentParams),
rgrover1 17:e2c0a1696e39 97 sizeof(PersistentParams_t),
rgrover1 16:1daa78939a3b 98 0 /* offset */);
rgrover1 16:1daa78939a3b 99 } else {
rgrover1 16:1daa78939a3b 100 pstorage_update(&pstorageHandle,
rgrover1 17:e2c0a1696e39 101 reinterpret_cast<uint8_t *>(&persistentParams),
rgrover1 17:e2c0a1696e39 102 sizeof(PersistentParams_t),
rgrover1 16:1daa78939a3b 103 0 /* offset */);
rgrover1 16:1daa78939a3b 104 }
rgrover1 16:1daa78939a3b 105 }