Example program for the Eddystone Beacon service.
Dependencies: BLE_API mbed nRF51822 X_NUCLEO_IDB0XA1
Fork of BLE_EddystoneBeacon by
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.
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.
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.
EddystoneService.h@36:17b4a0ff9abb, 2016-09-20 (annotated)
- 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?
User | Revision | Line number | New 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 ¶msIn, |
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__ */ |