Example program for the Eddystone Beacon service.

Dependencies:   BLE_API mbed nRF51822 X_NUCLEO_IDB0XA1

Fork of BLE_EddystoneBeacon by URIBeacon

This example demonstrates how to set up and initialize a Eddystone Beacon. For more details on the Eddystone specification please see the Eddystone Github Page.

The Basics

An Eddystone Beacon is a Bluetooth Low Energy beacon, that means it does all of its data transfer in GAP advertising packets. Eddystone beacons, unlike other beacons, broadcast multiple types of data. Currently Eddystone beacons have 3 frame types (UID, URL, TLM) that will get swapped out periodically. This swapping of frame data allows Eddystone beacons to send many different types of data, thus increasing their usefulness over traditional beacons. Note that the UID frame type provides the same 16Bytes of UUID namespace that iBeacons do and the URL frame type provides the same functionality as a URIBeacon.

For more details see the Eddystone Specification.

Smartphone Apps

nRF Master Control Panel - this program recognizes Eddystone beacons and will display the data for all frame types.

iPhone Physical Web app

Android App

Walkthrough of Physical Web application

Technical Details

The Eddystone Specification looks like the following image. Please note that this may change over time and for up to date information the official spec should be referenced. /media/uploads/mbedAustin/scratch-1-.png

The Eddystone Frames get swapped in and out depending on what frames you have enabled. The only required frame type is the TLM frame, all others are optional and you can have any number enabled. To disable the UID or URL frames give their values a 'NULL' in the Eddystone constructor. The Eddystone spec recommends broadcasting 10 frames a second.

Note

  • The current Eddystone mbed example does not allow for combining the eddystone service with other services, this will be changes in a future update.
  • There is an Eddystone Config service that allows for updating beacons in the field. We are working on an example for this, so keep your eyes pealed for a future update.
Committer:
Vincent Coubard
Date:
Tue Sep 20 14:13:43 2016 +0100
Revision:
36:17b4a0ff9abb
Parent:
34:f6d4a699a1ea
Update libraries and add support of the ST shield.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andresag 34:f6d4a699a1ea 1 /* mbed Microcontroller Library
andresag 34:f6d4a699a1ea 2 * Copyright (c) 2006-2015 ARM Limited
andresag 34:f6d4a699a1ea 3 *
andresag 34:f6d4a699a1ea 4 * Licensed under the Apache License, Version 2.0 (the "License");
andresag 34:f6d4a699a1ea 5 * you may not use this file except in compliance with the License.
andresag 34:f6d4a699a1ea 6 * You may obtain a copy of the License at
andresag 34:f6d4a699a1ea 7 *
andresag 34:f6d4a699a1ea 8 * http://www.apache.org/licenses/LICENSE-2.0
andresag 34:f6d4a699a1ea 9 *
andresag 34:f6d4a699a1ea 10 * Unless required by applicable law or agreed to in writing, software
andresag 34:f6d4a699a1ea 11 * distributed under the License is distributed on an "AS IS" BASIS,
andresag 34:f6d4a699a1ea 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
andresag 34:f6d4a699a1ea 13 * See the License for the specific language governing permissions and
andresag 34:f6d4a699a1ea 14 * limitations under the License.
andresag 34:f6d4a699a1ea 15 */
andresag 34:f6d4a699a1ea 16
andresag 34:f6d4a699a1ea 17 #ifndef __EDDYSTONESERVICE_H__
andresag 34:f6d4a699a1ea 18 #define __EDDYSTONESERVICE_H__
andresag 34:f6d4a699a1ea 19
andresag 34:f6d4a699a1ea 20 #include "ble/BLE.h"
andresag 34:f6d4a699a1ea 21 #include "EddystoneTypes.h"
andresag 34:f6d4a699a1ea 22 #include "URLFrame.h"
andresag 34:f6d4a699a1ea 23 #include "UIDFrame.h"
andresag 34:f6d4a699a1ea 24 #include "TLMFrame.h"
andresag 34:f6d4a699a1ea 25 #include <string.h>
andresag 34:f6d4a699a1ea 26 #ifdef YOTTA_CFG_MBED_OS
andresag 34:f6d4a699a1ea 27 #include "mbed-drivers/mbed.h"
andresag 34:f6d4a699a1ea 28 #else
andresag 34:f6d4a699a1ea 29 #include "mbed.h"
andresag 34:f6d4a699a1ea 30 #endif
andresag 34:f6d4a699a1ea 31
andresag 34:f6d4a699a1ea 32 class EddystoneService
andresag 34:f6d4a699a1ea 33 {
andresag 34:f6d4a699a1ea 34 public:
andresag 34:f6d4a699a1ea 35 static const uint16_t TOTAL_CHARACTERISTICS = 9;
andresag 34:f6d4a699a1ea 36
andresag 34:f6d4a699a1ea 37 static const uint32_t DEFAULT_CONFIG_PERIOD_MSEC = 1000;
andresag 34:f6d4a699a1ea 38 static const uint16_t DEFAULT_BEACON_PERIOD_MSEC = 1000;
andresag 34:f6d4a699a1ea 39
andresag 34:f6d4a699a1ea 40 /* Operation modes of the EddystoneService:
andresag 34:f6d4a699a1ea 41 * NONE: EddystoneService has been initialised but no memory has been
andresag 34:f6d4a699a1ea 42 * dynamically allocated. Additionally, no services are running
andresag 34:f6d4a699a1ea 43 * nothing is being advertised.
andresag 34:f6d4a699a1ea 44 * CONFIG: EddystoneService has been initialised, the configuration
andresag 34:f6d4a699a1ea 45 * service started and memory has been allocated for BLE
andresag 34:f6d4a699a1ea 46 * characteristics. Memory consumption peaks during CONFIG
andresag 34:f6d4a699a1ea 47 * mode.
andresag 34:f6d4a699a1ea 48 * BEACON: Eddystone service is running as a beacon advertising URL,
andresag 34:f6d4a699a1ea 49 * UID and/or TLM frames depending on how it is configured.
andresag 34:f6d4a699a1ea 50 * Note: The main app can change the mode of EddystoneService at any point
andresag 34:f6d4a699a1ea 51 * of time by calling startConfigService() or startBeaconService().
andresag 34:f6d4a699a1ea 52 * Resources from the previous mode will be freed. It is currently NOT
andresag 34:f6d4a699a1ea 53 * possible to force EddystoneService back into MODE_NONE.
andresag 34:f6d4a699a1ea 54 */
andresag 34:f6d4a699a1ea 55 enum OperationModes {
andresag 34:f6d4a699a1ea 56 EDDYSTONE_MODE_NONE,
andresag 34:f6d4a699a1ea 57 EDDYSTONE_MODE_CONFIG,
andresag 34:f6d4a699a1ea 58 EDDYSTONE_MODE_BEACON
andresag 34:f6d4a699a1ea 59 };
andresag 34:f6d4a699a1ea 60
andresag 34:f6d4a699a1ea 61 struct EddystoneParams_t {
andresag 34:f6d4a699a1ea 62 bool lockState;
andresag 34:f6d4a699a1ea 63 Lock_t lock;
andresag 34:f6d4a699a1ea 64 Lock_t unlock;
andresag 34:f6d4a699a1ea 65 uint8_t flags;
andresag 34:f6d4a699a1ea 66 PowerLevels_t advPowerLevels;
andresag 34:f6d4a699a1ea 67 uint8_t txPowerMode;
andresag 34:f6d4a699a1ea 68 uint16_t beaconPeriod;
andresag 34:f6d4a699a1ea 69 uint8_t tlmVersion;
andresag 34:f6d4a699a1ea 70 uint8_t urlDataLength;
andresag 34:f6d4a699a1ea 71 UrlData_t urlData;
andresag 34:f6d4a699a1ea 72 UIDNamespaceID_t uidNamespaceID;
andresag 34:f6d4a699a1ea 73 UIDInstanceID_t uidInstanceID;
andresag 34:f6d4a699a1ea 74 };
andresag 34:f6d4a699a1ea 75
andresag 34:f6d4a699a1ea 76 enum EddystoneError_t {
andresag 34:f6d4a699a1ea 77 EDDYSTONE_ERROR_NONE,
andresag 34:f6d4a699a1ea 78 EDDYSTONE_ERROR_INVALID_BEACON_PERIOD,
andresag 34:f6d4a699a1ea 79 EDDYSTONE_ERROR_INVALID_CONSEC_FRAMES,
andresag 34:f6d4a699a1ea 80 EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL
andresag 34:f6d4a699a1ea 81 };
andresag 34:f6d4a699a1ea 82
andresag 34:f6d4a699a1ea 83 enum FrameType {
andresag 34:f6d4a699a1ea 84 EDDYSTONE_FRAME_URL,
andresag 34:f6d4a699a1ea 85 EDDYSTONE_FRAME_UID,
andresag 34:f6d4a699a1ea 86 EDDYSTONE_FRAME_TLM,
andresag 34:f6d4a699a1ea 87 NUM_EDDYSTONE_FRAMES
andresag 34:f6d4a699a1ea 88 };
andresag 34:f6d4a699a1ea 89
andresag 34:f6d4a699a1ea 90 /* Initialise the EddystoneService using parameters from persistent storage */
andresag 34:f6d4a699a1ea 91 EddystoneService(BLE &bleIn,
andresag 34:f6d4a699a1ea 92 EddystoneParams_t &paramsIn,
andresag 34:f6d4a699a1ea 93 const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 94 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 95 uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
andresag 34:f6d4a699a1ea 96
andresag 34:f6d4a699a1ea 97 /* When using this constructor we need to call setURLData,
andresag 34:f6d4a699a1ea 98 * setTMLData and setUIDData to initialise values manually
andresag 34:f6d4a699a1ea 99 */
andresag 34:f6d4a699a1ea 100 EddystoneService(BLE &bleIn,
andresag 34:f6d4a699a1ea 101 const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 102 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 103 uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
andresag 34:f6d4a699a1ea 104
andresag 34:f6d4a699a1ea 105 /* Setup callback to update BatteryVoltage in TLM frame */
andresag 34:f6d4a699a1ea 106 void onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn);
andresag 34:f6d4a699a1ea 107
andresag 34:f6d4a699a1ea 108 /* Setup callback to update BeaconTemperature in TLM frame */
andresag 34:f6d4a699a1ea 109 void onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn);
andresag 34:f6d4a699a1ea 110
andresag 34:f6d4a699a1ea 111 void setTLMData(uint8_t tlmVersionIn = 0);
andresag 34:f6d4a699a1ea 112
andresag 34:f6d4a699a1ea 113 void setURLData(const char *urlDataIn);
andresag 34:f6d4a699a1ea 114
andresag 34:f6d4a699a1ea 115 void setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn);
andresag 34:f6d4a699a1ea 116
andresag 34:f6d4a699a1ea 117 EddystoneError_t startConfigService(void);
andresag 34:f6d4a699a1ea 118
andresag 34:f6d4a699a1ea 119 EddystoneError_t startBeaconService(uint16_t consecUrlFramesIn = 2, uint16_t consecUidFramesIn = 2, uint16_t consecTlmFramesIn = 2);
andresag 34:f6d4a699a1ea 120
andresag 34:f6d4a699a1ea 121 /* It is not the responsibility of the Eddystone implementation to store
andresag 34:f6d4a699a1ea 122 * the configured parameters in persistent storage since this is
andresag 34:f6d4a699a1ea 123 * platform-specific. So we provide this function that returns the
andresag 34:f6d4a699a1ea 124 * configured values that need to be stored and the main application
andresag 34:f6d4a699a1ea 125 * takes care of storing them.
andresag 34:f6d4a699a1ea 126 */
andresag 34:f6d4a699a1ea 127 void getEddystoneParams(EddystoneParams_t *params);
andresag 34:f6d4a699a1ea 128
andresag 34:f6d4a699a1ea 129 private:
andresag 34:f6d4a699a1ea 130 /* Helper function used only once during constructing the object to avoid
andresag 34:f6d4a699a1ea 131 * duplicated code.
andresag 34:f6d4a699a1ea 132 */
andresag 34:f6d4a699a1ea 133 void eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn,
andresag 34:f6d4a699a1ea 134 const PowerLevels_t &radioPowerLevelsIn,
andresag 34:f6d4a699a1ea 135 uint32_t advConfigIntervalIn);
andresag 34:f6d4a699a1ea 136
andresag 34:f6d4a699a1ea 137 /* When changing modes, we shutdown and init the BLE instance, so
andresag 34:f6d4a699a1ea 138 * this is needed to complete the initialisation task.
andresag 34:f6d4a699a1ea 139 */
andresag 34:f6d4a699a1ea 140 void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext);
andresag 34:f6d4a699a1ea 141
andresag 34:f6d4a699a1ea 142 void swapAdvertisedFrame(void);
andresag 34:f6d4a699a1ea 143
andresag 34:f6d4a699a1ea 144 void updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength);
andresag 34:f6d4a699a1ea 145
andresag 34:f6d4a699a1ea 146 /* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
andresag 34:f6d4a699a1ea 147 * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
andresag 34:f6d4a699a1ea 148 * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
andresag 34:f6d4a699a1ea 149 * Eddystone specification.
andresag 34:f6d4a699a1ea 150 */
andresag 34:f6d4a699a1ea 151 void updateRawTLMFrame(void);
andresag 34:f6d4a699a1ea 152
andresag 34:f6d4a699a1ea 153 void setupBeaconService(void);
andresag 34:f6d4a699a1ea 154
andresag 34:f6d4a699a1ea 155 void setupConfigService(void);
andresag 34:f6d4a699a1ea 156
andresag 34:f6d4a699a1ea 157 void freeConfigCharacteristics(void);
andresag 34:f6d4a699a1ea 158
andresag 34:f6d4a699a1ea 159 void freeBeaconFrames(void);
andresag 34:f6d4a699a1ea 160
andresag 34:f6d4a699a1ea 161 void radioNotificationCallback(bool radioActive);
andresag 34:f6d4a699a1ea 162
andresag 34:f6d4a699a1ea 163 /*
andresag 34:f6d4a699a1ea 164 * Internal helper function used to update the GATT database following any
andresag 34:f6d4a699a1ea 165 * change to the internal state of the service object.
andresag 34:f6d4a699a1ea 166 */
andresag 34:f6d4a699a1ea 167 void updateCharacteristicValues(void);
andresag 34:f6d4a699a1ea 168
andresag 34:f6d4a699a1ea 169 void setupEddystoneConfigAdvertisements(void);
andresag 34:f6d4a699a1ea 170
andresag 34:f6d4a699a1ea 171 void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
andresag 34:f6d4a699a1ea 172
andresag 34:f6d4a699a1ea 173 void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
andresag 34:f6d4a699a1ea 174
andresag 34:f6d4a699a1ea 175 void urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
andresag 34:f6d4a699a1ea 176
andresag 34:f6d4a699a1ea 177 void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
andresag 34:f6d4a699a1ea 178
andresag 34:f6d4a699a1ea 179 template <typename T>
andresag 34:f6d4a699a1ea 180 void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
andresag 34:f6d4a699a1ea 181
andresag 34:f6d4a699a1ea 182 /*
andresag 34:f6d4a699a1ea 183 * This callback is invoked when a GATT client attempts to modify any of the
andresag 34:f6d4a699a1ea 184 * characteristics of this service. Attempts to do so are also applied to
andresag 34:f6d4a699a1ea 185 * the internal state of this service object.
andresag 34:f6d4a699a1ea 186 */
andresag 34:f6d4a699a1ea 187 void onDataWrittenCallback(const GattWriteCallbackParams *writeParams);
andresag 34:f6d4a699a1ea 188
andresag 34:f6d4a699a1ea 189 uint16_t correctAdvertisementPeriod(uint16_t beaconPeriodIn) const;
andresag 34:f6d4a699a1ea 190
andresag 34:f6d4a699a1ea 191 BLE &ble;
andresag 34:f6d4a699a1ea 192 uint32_t advConfigInterval;
andresag 34:f6d4a699a1ea 193 uint8_t operationMode;
andresag 34:f6d4a699a1ea 194
andresag 34:f6d4a699a1ea 195 URLFrame urlFrame;
andresag 34:f6d4a699a1ea 196 UIDFrame uidFrame;
andresag 34:f6d4a699a1ea 197 TLMFrame tlmFrame;
andresag 34:f6d4a699a1ea 198
andresag 34:f6d4a699a1ea 199 PowerLevels_t radioPowerLevels;
andresag 34:f6d4a699a1ea 200 PowerLevels_t advPowerLevels;
andresag 34:f6d4a699a1ea 201 bool lockState;
andresag 34:f6d4a699a1ea 202 bool resetFlag;
andresag 34:f6d4a699a1ea 203 Lock_t lock;
andresag 34:f6d4a699a1ea 204 Lock_t unlock;
andresag 34:f6d4a699a1ea 205 uint8_t flags;
andresag 34:f6d4a699a1ea 206 uint8_t txPowerMode;
andresag 34:f6d4a699a1ea 207 uint16_t beaconPeriod;
andresag 34:f6d4a699a1ea 208
andresag 34:f6d4a699a1ea 209 ReadOnlyGattCharacteristic<bool> *lockStateChar;
andresag 34:f6d4a699a1ea 210 WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)> *lockChar;
andresag 34:f6d4a699a1ea 211 WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)> *unlockChar;
andresag 34:f6d4a699a1ea 212 GattCharacteristic *urlDataChar;
andresag 34:f6d4a699a1ea 213 ReadWriteGattCharacteristic<uint8_t> *flagsChar;
andresag 34:f6d4a699a1ea 214 ReadWriteArrayGattCharacteristic<int8_t, sizeof(PowerLevels_t)> *advPowerLevelsChar;
andresag 34:f6d4a699a1ea 215 ReadWriteGattCharacteristic<uint8_t> *txPowerModeChar;
andresag 34:f6d4a699a1ea 216 ReadWriteGattCharacteristic<uint16_t> *beaconPeriodChar;
andresag 34:f6d4a699a1ea 217 WriteOnlyGattCharacteristic<bool> *resetChar;
andresag 34:f6d4a699a1ea 218
andresag 34:f6d4a699a1ea 219 uint8_t *rawUrlFrame;
andresag 34:f6d4a699a1ea 220 uint8_t *rawUidFrame;
andresag 34:f6d4a699a1ea 221 uint8_t *rawTlmFrame;
andresag 34:f6d4a699a1ea 222
andresag 34:f6d4a699a1ea 223 uint16_t consecFrames[NUM_EDDYSTONE_FRAMES];
andresag 34:f6d4a699a1ea 224 uint16_t currentConsecFrames[NUM_EDDYSTONE_FRAMES];
andresag 34:f6d4a699a1ea 225 uint8_t currentAdvertisedFrame;
andresag 34:f6d4a699a1ea 226
andresag 34:f6d4a699a1ea 227 TlmUpdateCallback_t tlmBatteryVoltageCallback;
andresag 34:f6d4a699a1ea 228 TlmUpdateCallback_t tlmBeaconTemperatureCallback;
andresag 34:f6d4a699a1ea 229
andresag 34:f6d4a699a1ea 230 Timer timeSinceBootTimer;
andresag 34:f6d4a699a1ea 231 #ifndef YOTTA_CFG_MBED_OS
andresag 34:f6d4a699a1ea 232 Timeout swapAdvertisedFrameTimeout;
andresag 34:f6d4a699a1ea 233 #endif
andresag 34:f6d4a699a1ea 234
andresag 34:f6d4a699a1ea 235 GattCharacteristic *charTable[TOTAL_CHARACTERISTICS];
andresag 34:f6d4a699a1ea 236 };
andresag 34:f6d4a699a1ea 237
andresag 34:f6d4a699a1ea 238 #endif /* __EDDYSTONESERVICE_H__ */