Bluetooth Low Energy / Mbed 2 deprecated BLE_EddystoneBeacon_Service Featured

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:
mbedAustin
Date:
Fri Jul 24 04:07:34 2015 +0000
Revision:
30:6c2db8bf5b17
Parent:
29:dfb7fb5a971b
[[Working]] Updated main program to periodically update the temperature and battery voltage.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbedAustin 26:2896fbdd0450 1 /* mbed Microcontroller Library
mbedAustin 26:2896fbdd0450 2 * Copyright (c) 2006-2013 ARM Limited
mbedAustin 26:2896fbdd0450 3 *
mbedAustin 26:2896fbdd0450 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbedAustin 26:2896fbdd0450 5 * you may not use this file except in compliance with the License.
mbedAustin 26:2896fbdd0450 6 * You may obtain a copy of the License at
mbedAustin 26:2896fbdd0450 7 *
mbedAustin 26:2896fbdd0450 8 * http://www.apache.org/licenses/LICENSE-2.0
mbedAustin 26:2896fbdd0450 9 *
mbedAustin 26:2896fbdd0450 10 * Unless required by applicable law or agreed to in writing, software
mbedAustin 26:2896fbdd0450 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbedAustin 26:2896fbdd0450 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbedAustin 26:2896fbdd0450 13 * See the License for the specific language governing permissions and
mbedAustin 26:2896fbdd0450 14 * limitations under the License.
mbedAustin 26:2896fbdd0450 15 */
mbedAustin 26:2896fbdd0450 16
mbedAustin 26:2896fbdd0450 17 #ifndef SERVICES_EDDYSTONEBEACON_H_
mbedAustin 26:2896fbdd0450 18 #define SERVICES_EDDYSTONEBEACON_H_
mbedAustin 26:2896fbdd0450 19
mbedAustin 26:2896fbdd0450 20 #include "ble/BLE.h"
mbedAustin 26:2896fbdd0450 21 #include "mbed.h"
mbedAustin 26:2896fbdd0450 22
mbedAustin 26:2896fbdd0450 23 static const uint8_t BEACON_EDDYSTONE[] = {0xAA, 0xFE};
mbedAustin 26:2896fbdd0450 24
mbedAustin 26:2896fbdd0450 25 //Debug is disabled by default
mbedAustin 30:6c2db8bf5b17 26 #if 0
mbedAustin 26:2896fbdd0450 27 #define DBG(x, ...) printf("[EddyStone: DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
mbedAustin 26:2896fbdd0450 28 #define WARN(x, ...) printf("[EddyStone: WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
mbedAustin 26:2896fbdd0450 29 #define ERR(x, ...) printf("[EddyStone: ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
mbedAustin 26:2896fbdd0450 30 #else
mbedAustin 26:2896fbdd0450 31 #define DBG(x, ...) //wait_us(10);
mbedAustin 26:2896fbdd0450 32 #define WARN(x, ...) //wait_us(10);
mbedAustin 26:2896fbdd0450 33 #define ERR(x, ...)
mbedAustin 30:6c2db8bf5b17 34 #endif
mbedAustin 30:6c2db8bf5b17 35
mbedAustin 30:6c2db8bf5b17 36 #if 1
mbedAustin 30:6c2db8bf5b17 37 #define INFO(x, ...) printf("[EddyStone: INFO]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__);
mbedAustin 30:6c2db8bf5b17 38 #else
mbedAustin 29:dfb7fb5a971b 39 #define INFO(x, ...)
mbedAustin 26:2896fbdd0450 40 #endif
mbedAustin 26:2896fbdd0450 41
mbedAustin 26:2896fbdd0450 42 /**
mbedAustin 26:2896fbdd0450 43 * @class Eddystone
mbedAustin 26:2896fbdd0450 44 * @brief Eddystone Configuration Service. Can be used to set URL, adjust power levels, and set flags.
mbedAustin 26:2896fbdd0450 45 * See https://github.com/google/eddystone
mbedAustin 26:2896fbdd0450 46 *
mbedAustin 26:2896fbdd0450 47 */
mbedAustin 28:af37cebcb583 48 class EddystoneService
mbedAustin 26:2896fbdd0450 49 {
mbedAustin 26:2896fbdd0450 50 public:
mbedAustin 26:2896fbdd0450 51 /**
mbedAustin 26:2896fbdd0450 52 * @brief Transmission Power Modes for UriBeacon
mbedAustin 26:2896fbdd0450 53 */
mbedAustin 26:2896fbdd0450 54
mbedAustin 26:2896fbdd0450 55 static const int ADVERTISING_INTERVAL_MSEC = 1000; // Advertising interval for config service.
mbedAustin 26:2896fbdd0450 56 static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets
mbedAustin 26:2896fbdd0450 57
mbedAustin 26:2896fbdd0450 58 // There are currently 3 subframes defined, URI, UID, and TLM
mbedAustin 26:2896fbdd0450 59 #define EDDYSTONE_MAX_FRAMETYPE 3
mbedAustin 26:2896fbdd0450 60 void (*frames[EDDYSTONE_MAX_FRAMETYPE])(uint8_t *, uint32_t);
mbedAustin 26:2896fbdd0450 61 uint8_t frameIndex;
mbedAustin 26:2896fbdd0450 62 static const int URI_DATA_MAX = 18;
mbedAustin 26:2896fbdd0450 63 typedef uint8_t UriData_t[URI_DATA_MAX];
mbedAustin 26:2896fbdd0450 64
mbedAustin 26:2896fbdd0450 65 // UID Frame Type subfields
mbedAustin 26:2896fbdd0450 66 static const int UID_NAMESPACEID_SIZE = 10;
mbedAustin 26:2896fbdd0450 67 typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
mbedAustin 26:2896fbdd0450 68 static const int UID_INSTANCEID_SIZE = 6;
mbedAustin 26:2896fbdd0450 69 typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
mbedAustin 26:2896fbdd0450 70
mbedAustin 26:2896fbdd0450 71 // Eddystone Frame Type ID
mbedAustin 26:2896fbdd0450 72 static const uint8_t FRAME_TYPE_UID = 0x00;
mbedAustin 26:2896fbdd0450 73 static const uint8_t FRAME_TYPE_URL = 0x10;
mbedAustin 26:2896fbdd0450 74 static const uint8_t FRAME_TYPE_TLM = 0x20;
mbedAustin 26:2896fbdd0450 75
mbedAustin 26:2896fbdd0450 76 static const uint8_t FRAME_SIZE_TLM = 14; // TLM frame is a constant 14Bytes
mbedAustin 26:2896fbdd0450 77 static const uint8_t FRAME_SIZE_UID = 20; // includes RFU bytes
mbedAustin 26:2896fbdd0450 78
mbedAustin 26:2896fbdd0450 79 /*
mbedAustin 26:2896fbdd0450 80 * Set Eddystone UID Frame information.
mbedAustin 26:2896fbdd0450 81 * @param[in] power TX Power in dB measured at 0 meters from the device. Range of -100 to +20 dB.
mbedAustin 26:2896fbdd0450 82 * @param namespaceID 10B namespace ID
mbedAustin 26:2896fbdd0450 83 * @param instanceID 6B instance ID
mbedAustin 26:2896fbdd0450 84 * @param RFU 2B of RFU, initialized to 0x0000 and not broadcast, included for future reference.
mbedAustin 26:2896fbdd0450 85 *
mbedAustin 26:2896fbdd0450 86 */
mbedAustin 26:2896fbdd0450 87 void setUIDFrameData(int8_t power, UIDNamespaceID_t namespaceID, UIDInstanceID_t instanceID, uint16_t RFU = 0x0000) {
mbedAustin 26:2896fbdd0450 88 if(power > 20) {
mbedAustin 26:2896fbdd0450 89 power = 20;
mbedAustin 26:2896fbdd0450 90 }
mbedAustin 26:2896fbdd0450 91 if(power < -100) {
mbedAustin 26:2896fbdd0450 92 power = -100;
mbedAustin 26:2896fbdd0450 93 }
mbedAustin 26:2896fbdd0450 94 defaultUidPower = power;
mbedAustin 26:2896fbdd0450 95 memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE);
mbedAustin 26:2896fbdd0450 96 memcpy(defaultUidInstanceID, instanceID, UID_INSTANCEID_SIZE);
mbedAustin 26:2896fbdd0450 97 uidRFU = (uint16_t)RFU; // this is probably bad form, but it doesnt really matter yet.
mbedAustin 26:2896fbdd0450 98 return;
mbedAustin 26:2896fbdd0450 99 }
mbedAustin 26:2896fbdd0450 100
mbedAustin 26:2896fbdd0450 101 /*
mbedAustin 26:2896fbdd0450 102 * Construct UID frame from private variables
mbedAustin 26:2896fbdd0450 103 * @param[in/out] Data pointer to array to store constructed frame in
mbedAustin 26:2896fbdd0450 104 * @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to
mbedAustin 26:2896fbdd0450 105 * @return number of bytes used. negative number indicates error message.
mbedAustin 26:2896fbdd0450 106 */
mbedAustin 26:2896fbdd0450 107 int constructUIDFrame(uint8_t * Data, uint8_t maxSize) {
mbedAustin 26:2896fbdd0450 108
mbedAustin 26:2896fbdd0450 109 int index = 0;
mbedAustin 26:2896fbdd0450 110 Data[index++] = FRAME_TYPE_UID; // 1B Type
mbedAustin 26:2896fbdd0450 111 if(defaultUidPower > 20) {
mbedAustin 26:2896fbdd0450 112 defaultUidPower = 20; // enforce range of vaild values.
mbedAustin 26:2896fbdd0450 113 }
mbedAustin 26:2896fbdd0450 114 if(defaultUidPower < -100) {
mbedAustin 26:2896fbdd0450 115 defaultUidPower = -100;
mbedAustin 26:2896fbdd0450 116 }
mbedAustin 26:2896fbdd0450 117 Data[index++] = defaultUidPower; // 1B Power @ 0meter
mbedAustin 26:2896fbdd0450 118 for(int x = 0; x < UID_NAMESPACEID_SIZE; x++) { // 10B Namespce ID
mbedAustin 26:2896fbdd0450 119 Data[index++] = defaultUidNamespaceID[x];
mbedAustin 26:2896fbdd0450 120 }
mbedAustin 26:2896fbdd0450 121 for(int x = 0; x< UID_INSTANCEID_SIZE; x++) { // 6B Instance ID
mbedAustin 26:2896fbdd0450 122 Data[index++] = defaultUidInstanceID[x];
mbedAustin 26:2896fbdd0450 123 }
mbedAustin 26:2896fbdd0450 124 if(0 != uidRFU) { // 2B RFU, include if non-zero, otherwise ignore
mbedAustin 26:2896fbdd0450 125 Data[index++] = (uint8_t)(uidRFU >> 0);
mbedAustin 26:2896fbdd0450 126 Data[index++] = (uint8_t)(uidRFU >> 8);
mbedAustin 26:2896fbdd0450 127 }
mbedAustin 26:2896fbdd0450 128 DBG("construcUIDFrame %d, %d",maxSize,index);
mbedAustin 26:2896fbdd0450 129 return index;
mbedAustin 26:2896fbdd0450 130 }
mbedAustin 26:2896fbdd0450 131
mbedAustin 26:2896fbdd0450 132 /*
mbedAustin 26:2896fbdd0450 133 * Set Eddystone URL Frame information.
mbedAustin 26:2896fbdd0450 134 * @param[in] power TX Power in dB measured at 0 meters from the device.
mbedAustin 26:2896fbdd0450 135 * @param url URL to encode
mbedAustin 26:2896fbdd0450 136 * @return false on success, true on failure.
mbedAustin 26:2896fbdd0450 137 */
mbedAustin 26:2896fbdd0450 138 bool setURLFrameData(int8_t power, const char * url) {
mbedAustin 26:2896fbdd0450 139 defaultUrlPower = power;
mbedAustin 29:dfb7fb5a971b 140 encodeURL(url, defaultUriData, defaultUriDataLength); // encode URL to URL Formatting
mbedAustin 26:2896fbdd0450 141 if (defaultUriDataLength > URI_DATA_MAX) {
mbedAustin 26:2896fbdd0450 142 return true; // error, URL is too big
mbedAustin 26:2896fbdd0450 143 }
mbedAustin 26:2896fbdd0450 144 return false;
mbedAustin 26:2896fbdd0450 145 }
mbedAustin 26:2896fbdd0450 146
mbedAustin 26:2896fbdd0450 147 /*
mbedAustin 26:2896fbdd0450 148 * Construct URL frame from private variables
mbedAustin 26:2896fbdd0450 149 * @param[in/out] Data pointer to array to store constructed frame in
mbedAustin 26:2896fbdd0450 150 * @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to
mbedAustin 26:2896fbdd0450 151 * @return number of bytes used. negative number indicates error message.
mbedAustin 26:2896fbdd0450 152 */
mbedAustin 26:2896fbdd0450 153 int constructURLFrame(uint8_t * Data, uint8_t maxSize) {
mbedAustin 26:2896fbdd0450 154 int index = 0;
mbedAustin 26:2896fbdd0450 155 Data[index++] = FRAME_TYPE_URL; // 1B Type
mbedAustin 26:2896fbdd0450 156 Data[index++] = defaultUrlPower; // 1B TX Power
mbedAustin 26:2896fbdd0450 157 for(int x = 0; x < defaultUriDataLength; x++) { // 18B of URL Prefix + encoded URL
mbedAustin 26:2896fbdd0450 158 Data[index++] = defaultUriData[x];
mbedAustin 26:2896fbdd0450 159 }
mbedAustin 26:2896fbdd0450 160 DBG("constructURLFrame: %d, %d",maxSize,index);
mbedAustin 26:2896fbdd0450 161 return index;
mbedAustin 26:2896fbdd0450 162 }
mbedAustin 26:2896fbdd0450 163
mbedAustin 26:2896fbdd0450 164 /*
mbedAustin 26:2896fbdd0450 165 * Set Eddystone TLM Frame information.
mbedAustin 26:2896fbdd0450 166 * @param[in] Version of the TLM beacon data format
mbedAustin 26:2896fbdd0450 167 * @param batteryVoltage in milivolts
mbedAustin 26:2896fbdd0450 168 * @param beaconTemp in 8.8 floating point notation
mbedAustin 26:2896fbdd0450 169 *
mbedAustin 26:2896fbdd0450 170 */
mbedAustin 26:2896fbdd0450 171 void setTLMFrameData(uint8_t version, uint16_t batteryVoltage, uint16_t beaconTemp, uint32_t pduCount = 0, uint32_t timeSinceBoot = 0) {
mbedAustin 26:2896fbdd0450 172 TlmVersion = version;
mbedAustin 26:2896fbdd0450 173 TlmBatteryVoltage = batteryVoltage;
mbedAustin 26:2896fbdd0450 174 TlmBeaconTemp = beaconTemp;
mbedAustin 26:2896fbdd0450 175 TlmPduCount = pduCount; // reset
mbedAustin 26:2896fbdd0450 176 TlmTimeSinceBoot = timeSinceBoot; // reset
mbedAustin 26:2896fbdd0450 177 return;
mbedAustin 26:2896fbdd0450 178 }
mbedAustin 26:2896fbdd0450 179
mbedAustin 26:2896fbdd0450 180 /*
mbedAustin 26:2896fbdd0450 181 * Construct TLM frame from private variables
mbedAustin 26:2896fbdd0450 182 * @param[in/out] Data pointer to array to store constructed frame in
mbedAustin 26:2896fbdd0450 183 * @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to
mbedAustin 26:2896fbdd0450 184 * @return number of bytes used. negative number indicates error message.
mbedAustin 26:2896fbdd0450 185 */
mbedAustin 26:2896fbdd0450 186 int constructTLMFrame(uint8_t * Data, uint8_t maxSize) {
mbedAustin 26:2896fbdd0450 187 int index = 0;
mbedAustin 26:2896fbdd0450 188 Data[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry
mbedAustin 26:2896fbdd0450 189 Data[index++] = TlmVersion; // TLM Version Number
mbedAustin 26:2896fbdd0450 190 Data[index++] = (uint8_t)(TlmBatteryVoltage>>8); // Battery Voltage[0]
mbedAustin 26:2896fbdd0450 191 Data[index++] = (uint8_t)(TlmBatteryVoltage>>0); // Battery Voltage[1]
mbedAustin 26:2896fbdd0450 192 Data[index++] = (uint8_t)(TlmBeaconTemp>>8); // Beacon Temp[0]
mbedAustin 26:2896fbdd0450 193 Data[index++] = (uint8_t)(TlmBeaconTemp>>0); // Beacon Temp[1]
mbedAustin 26:2896fbdd0450 194 Data[index++] = (uint8_t)(TlmPduCount>>24); // PDU Count [0]
mbedAustin 26:2896fbdd0450 195 Data[index++] = (uint8_t)(TlmPduCount>>16); // PDU Count [1]
mbedAustin 26:2896fbdd0450 196 Data[index++] = (uint8_t)(TlmPduCount>>8); // PDU Count [2]
mbedAustin 26:2896fbdd0450 197 Data[index++] = (uint8_t)(TlmPduCount>>0); // PDU Count [3]
mbedAustin 26:2896fbdd0450 198 Data[index++] = (uint8_t)(TlmTimeSinceBoot>>24); // Time Since Boot [0]
mbedAustin 26:2896fbdd0450 199 Data[index++] = (uint8_t)(TlmTimeSinceBoot>>16); // Time Since Boot [1]
mbedAustin 26:2896fbdd0450 200 Data[index++] = (uint8_t)(TlmTimeSinceBoot>>8); // Time Since Boot [2]
mbedAustin 26:2896fbdd0450 201 Data[index++] = (uint8_t)(TlmTimeSinceBoot>>0); // Time Since Boot [3]
mbedAustin 26:2896fbdd0450 202 DBG("constructURLFrame: %d, %d",maxSize,index);
mbedAustin 26:2896fbdd0450 203 return index;
mbedAustin 26:2896fbdd0450 204 }
mbedAustin 26:2896fbdd0450 205
mbedAustin 26:2896fbdd0450 206 /*
mbedAustin 26:2896fbdd0450 207 * Update the TLM frame battery voltage value
mbedAustin 26:2896fbdd0450 208 * @param[in] voltagemv Voltage to update the TLM field battery voltage with (in mV)
mbedAustin 26:2896fbdd0450 209 * @return nothing
mbedAustin 26:2896fbdd0450 210 */
mbedAustin 26:2896fbdd0450 211 void updateTlmBatteryVoltage(uint16_t voltagemv) {
mbedAustin 26:2896fbdd0450 212 TlmBatteryVoltage = voltagemv;
mbedAustin 26:2896fbdd0450 213 return;
mbedAustin 26:2896fbdd0450 214 }
mbedAustin 26:2896fbdd0450 215
mbedAustin 26:2896fbdd0450 216 /*
mbedAustin 26:2896fbdd0450 217 * Update the TLM frame beacon temperature
mbedAustin 26:2896fbdd0450 218 * @param[in] temp Temperature of beacon (in 8.8fpn)
mbedAustin 26:2896fbdd0450 219 * @return nothing
mbedAustin 26:2896fbdd0450 220 */
mbedAustin 26:2896fbdd0450 221 void updateTlmBeaconTemp(uint16_t temp) {
mbedAustin 26:2896fbdd0450 222 TlmBeaconTemp = temp;
mbedAustin 26:2896fbdd0450 223 return;
mbedAustin 26:2896fbdd0450 224 }
mbedAustin 26:2896fbdd0450 225
mbedAustin 26:2896fbdd0450 226 /*
mbedAustin 26:2896fbdd0450 227 * Update the TLM frame PDU Count field
mbedAustin 26:2896fbdd0450 228 * @param[in] pduCount Number of Advertisiting frames sent since powerup
mbedAustin 26:2896fbdd0450 229 * @return nothing
mbedAustin 26:2896fbdd0450 230 */
mbedAustin 26:2896fbdd0450 231 void updateTlmPduCount(uint32_t pduCount) {
mbedAustin 26:2896fbdd0450 232 TlmPduCount = pduCount;
mbedAustin 26:2896fbdd0450 233 return;
mbedAustin 26:2896fbdd0450 234 }
mbedAustin 26:2896fbdd0450 235
mbedAustin 26:2896fbdd0450 236 /*
mbedAustin 26:2896fbdd0450 237 * Update the TLM frame Time since boot in 0.1s incriments
mbedAustin 26:2896fbdd0450 238 * @param[in] timeSinceBoot Time since boot in 0.1s incriments
mbedAustin 26:2896fbdd0450 239 * @return nothing
mbedAustin 26:2896fbdd0450 240 */
mbedAustin 26:2896fbdd0450 241 void updateTlmTimeSinceBoot(uint32_t timeSinceBoot) {
mbedAustin 26:2896fbdd0450 242 TlmTimeSinceBoot = timeSinceBoot;
mbedAustin 26:2896fbdd0450 243 return;
mbedAustin 26:2896fbdd0450 244 }
mbedAustin 26:2896fbdd0450 245
mbedAustin 26:2896fbdd0450 246 /*
mbedAustin 26:2896fbdd0450 247 * callback function, called every 0.1s, incriments the TimeSinceBoot field in the TLM frame
mbedAustin 26:2896fbdd0450 248 * @return nothing
mbedAustin 26:2896fbdd0450 249 */
mbedAustin 26:2896fbdd0450 250 void tsbCallback(void) {
mbedAustin 26:2896fbdd0450 251 TlmTimeSinceBoot++;
mbedAustin 26:2896fbdd0450 252 }
mbedAustin 26:2896fbdd0450 253
mbedAustin 26:2896fbdd0450 254 /*
mbedAustin 26:2896fbdd0450 255 * Update advertising data
mbedAustin 26:2896fbdd0450 256 * @return true on success, false on failure
mbedAustin 26:2896fbdd0450 257 */
mbedAustin 26:2896fbdd0450 258 bool updateAdvPacket(uint8_t serviceData[], unsigned serviceDataLen) {
mbedAustin 26:2896fbdd0450 259 // Fields from the Service
mbedAustin 26:2896fbdd0450 260 DBG("Updating AdvFrame: %d", serviceDataLen);
mbedAustin 30:6c2db8bf5b17 261 // printf("\r\n");
mbedAustin 30:6c2db8bf5b17 262 // for(int x = 0; x<serviceDataLen; x++) {
mbedAustin 30:6c2db8bf5b17 263 // printf("%2.2x:",serviceData[x]);
mbedAustin 30:6c2db8bf5b17 264 // }
mbedAustin 30:6c2db8bf5b17 265 // printf("\r\n");
mbedAustin 26:2896fbdd0450 266 ble.clearAdvertisingPayload();
mbedAustin 26:2896fbdd0450 267 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
mbedAustin 26:2896fbdd0450 268 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_EDDYSTONE, sizeof(BEACON_EDDYSTONE));
mbedAustin 26:2896fbdd0450 269 ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
mbedAustin 26:2896fbdd0450 270
mbedAustin 26:2896fbdd0450 271 return true;
mbedAustin 26:2896fbdd0450 272 }
mbedAustin 26:2896fbdd0450 273
mbedAustin 26:2896fbdd0450 274 /*
mbedAustin 26:2896fbdd0450 275 * State machine for switching out frames.
mbedAustin 26:2896fbdd0450 276 * This function is called by the radioNotificationCallback when a frame needs to get swapped out.
mbedAustin 26:2896fbdd0450 277 * This function exists because of time constraints in the radioNotificationCallback, so it is effectively
mbedAustin 26:2896fbdd0450 278 * broken up into two functions.
mbedAustin 26:2896fbdd0450 279 */
mbedAustin 26:2896fbdd0450 280 void swapOutFrames(void) {
mbedAustin 26:2896fbdd0450 281 uint8_t serviceData[SERVICE_DATA_MAX];
mbedAustin 26:2896fbdd0450 282 unsigned serviceDataLen = 0;
mbedAustin 26:2896fbdd0450 283 //hard code in the eddystone UUID
mbedAustin 26:2896fbdd0450 284 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0];
mbedAustin 26:2896fbdd0450 285 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1];
mbedAustin 26:2896fbdd0450 286
mbedAustin 26:2896fbdd0450 287 // if certain frames are not enabled, then skip them. Worst case TLM is always enabled
mbedAustin 26:2896fbdd0450 288 switch(frameIndex) {
mbedAustin 26:2896fbdd0450 289 case 1:
mbedAustin 26:2896fbdd0450 290 // URL Frame
mbedAustin 26:2896fbdd0450 291 if(urlIsSet) {
mbedAustin 30:6c2db8bf5b17 292 INFO("Swapping in URL Frame: Power: %d",defaultUrlPower);
mbedAustin 26:2896fbdd0450 293 serviceDataLen += constructURLFrame(serviceData+serviceDataLen,20);
mbedAustin 26:2896fbdd0450 294 DBG("\t Swapping in URL Frame: len=%d ",serviceDataLen);
mbedAustin 26:2896fbdd0450 295 updateAdvPacket(serviceData,serviceDataLen);
mbedAustin 26:2896fbdd0450 296 switchFlag = false;
mbedAustin 26:2896fbdd0450 297 frameIndex++;
mbedAustin 26:2896fbdd0450 298 break;
mbedAustin 26:2896fbdd0450 299 }
mbedAustin 26:2896fbdd0450 300 case 2:
mbedAustin 26:2896fbdd0450 301 // UID Frame
mbedAustin 26:2896fbdd0450 302 if(uidIsSet) {
mbedAustin 30:6c2db8bf5b17 303 INFO("Swapping in UID Frame: Power: %d",defaultUidPower);
mbedAustin 26:2896fbdd0450 304 serviceDataLen += constructUIDFrame(serviceData+serviceDataLen,20);
mbedAustin 26:2896fbdd0450 305 DBG("\t Swapping in UID Frame: len=%d",serviceDataLen);
mbedAustin 26:2896fbdd0450 306 updateAdvPacket(serviceData,serviceDataLen);
mbedAustin 26:2896fbdd0450 307 switchFlag = false;
mbedAustin 26:2896fbdd0450 308 frameIndex++;
mbedAustin 26:2896fbdd0450 309 break;
mbedAustin 26:2896fbdd0450 310 }
mbedAustin 26:2896fbdd0450 311 default:
mbedAustin 26:2896fbdd0450 312 // TLM frame
mbedAustin 30:6c2db8bf5b17 313 INFO("Swapping in TLM Frame: version=%x, Batt=%d, Temp = %d, PDUCnt = %d, TimeSinceBoot=%d",TlmVersion, TlmBatteryVoltage, TlmBeaconTemp, TlmPduCount, TlmTimeSinceBoot);
mbedAustin 26:2896fbdd0450 314 serviceDataLen += constructTLMFrame(serviceData+serviceDataLen,20);
mbedAustin 26:2896fbdd0450 315 DBG("\t Swapping in TLM Frame: len=%d",serviceDataLen);
mbedAustin 26:2896fbdd0450 316 updateAdvPacket(serviceData,serviceDataLen);
mbedAustin 26:2896fbdd0450 317 frameIndex++;
mbedAustin 26:2896fbdd0450 318 break;
mbedAustin 26:2896fbdd0450 319 }
mbedAustin 26:2896fbdd0450 320 }
mbedAustin 26:2896fbdd0450 321
mbedAustin 26:2896fbdd0450 322 /*
mbedAustin 26:2896fbdd0450 323 * Callback from onRadioNotification(), used to update the PDUCounter and process next state.
mbedAustin 26:2896fbdd0450 324 */
mbedAustin 26:2896fbdd0450 325 #define EDDYSTONE_SWAPFRAME_DELAYMS 1
mbedAustin 26:2896fbdd0450 326 void radioNotificationCallback(bool radioActive) {
mbedAustin 26:2896fbdd0450 327 //DBG("RadioNotificationCallback : %d, %d, %d, %d",radioActive,frameIndex,TlmPduCount,TlmTimeSinceBoot);
mbedAustin 26:2896fbdd0450 328 // Update PDUCount
mbedAustin 26:2896fbdd0450 329 TlmPduCount++;
mbedAustin 26:2896fbdd0450 330 frameIndex = frameIndex % EDDYSTONE_MAX_FRAMETYPE;
mbedAustin 26:2896fbdd0450 331
mbedAustin 26:2896fbdd0450 332
mbedAustin 26:2896fbdd0450 333 // True just before an frame is sent, fale just after a frame is sent
mbedAustin 26:2896fbdd0450 334 if(radioActive) {
mbedAustin 26:2896fbdd0450 335 // Do Nothing
mbedAustin 26:2896fbdd0450 336 } else {
mbedAustin 26:2896fbdd0450 337 // state machine to control which packet is being sent
mbedAustin 26:2896fbdd0450 338 switch(frameIndex) {
mbedAustin 26:2896fbdd0450 339 case 0: // TLM Frame
mbedAustin 28:af37cebcb583 340 switchFrame.attach_us(this, &EddystoneService::swapOutFrames, EDDYSTONE_SWAPFRAME_DELAYMS);
mbedAustin 26:2896fbdd0450 341 switchFlag = true;
mbedAustin 26:2896fbdd0450 342 break;
mbedAustin 26:2896fbdd0450 343 case 1: // URL Frame
mbedAustin 26:2896fbdd0450 344 // switch out packets
mbedAustin 26:2896fbdd0450 345 if(switchFlag) {
mbedAustin 28:af37cebcb583 346 switchFrame.attach_us(this, &EddystoneService::swapOutFrames, EDDYSTONE_SWAPFRAME_DELAYMS);
mbedAustin 26:2896fbdd0450 347 switchFlag = false;
mbedAustin 26:2896fbdd0450 348 } else {
mbedAustin 26:2896fbdd0450 349 if((TlmPduCount % 10) == 0) { // every 10 adv packets switch the frame
mbedAustin 26:2896fbdd0450 350 switchFlag = true;
mbedAustin 26:2896fbdd0450 351 }
mbedAustin 26:2896fbdd0450 352 }
mbedAustin 26:2896fbdd0450 353 break;
mbedAustin 26:2896fbdd0450 354 case 2: // UIDFrame
mbedAustin 26:2896fbdd0450 355 // switch out packets
mbedAustin 26:2896fbdd0450 356 if(switchFlag ) {
mbedAustin 28:af37cebcb583 357 switchFrame.attach_us(this, &EddystoneService::swapOutFrames, EDDYSTONE_SWAPFRAME_DELAYMS);
mbedAustin 26:2896fbdd0450 358 switchFlag = false;
mbedAustin 26:2896fbdd0450 359 } else {
mbedAustin 26:2896fbdd0450 360 if((TlmPduCount % 10) == 0) { // every 10 adv packets switch the frame
mbedAustin 26:2896fbdd0450 361 switchFlag = true;
mbedAustin 26:2896fbdd0450 362 }
mbedAustin 26:2896fbdd0450 363 }
mbedAustin 26:2896fbdd0450 364 break;
mbedAustin 26:2896fbdd0450 365 }
mbedAustin 26:2896fbdd0450 366 }
mbedAustin 26:2896fbdd0450 367
mbedAustin 26:2896fbdd0450 368 return;
mbedAustin 26:2896fbdd0450 369 }
mbedAustin 26:2896fbdd0450 370
mbedAustin 26:2896fbdd0450 371 /*
mbedAustin 26:2896fbdd0450 372 * This function explicityly sets the parameters used by the Eddystone beacon.
mbedAustin 26:2896fbdd0450 373 * this function should be used in leu of the config service.
mbedAustin 26:2896fbdd0450 374 *
mbedAustin 26:2896fbdd0450 375 * @param bleIn ble object used to broadcast eddystone information
mbedAustin 26:2896fbdd0450 376 * @oaram beaconPeriodus is how often ble broadcasts are mde, in mili seconds
mbedAustin 26:2896fbdd0450 377 * @param txPowerLevel sets the broadcasting power level.
mbedAustin 26:2896fbdd0450 378 * @param uidNamespaceID 10Byte Namespace UUID
mbedAustin 26:2896fbdd0450 379 * @param uidInstanceID 6Byte Instance UUID
mbedAustin 26:2896fbdd0450 380 * @param url shortened URL to broadcast (pass in as a string)
mbedAustin 26:2896fbdd0450 381 * @param urlLen length of shortened url
mbedAustin 26:2896fbdd0450 382 * @param tlmVersion version of telemetry data field to use (default to 0x00)
mbedAustin 26:2896fbdd0450 383 *
mbedAustin 26:2896fbdd0450 384 */
mbedAustin 28:af37cebcb583 385 EddystoneService(BLEDevice &bleIn,
mbedAustin 26:2896fbdd0450 386 uint16_t beaconPeriodus = 100,
mbedAustin 26:2896fbdd0450 387 uint8_t txPowerLevel = 0,
mbedAustin 26:2896fbdd0450 388 uint8_t * uidNamespaceID = NULL,
mbedAustin 26:2896fbdd0450 389 uint8_t * uidInstanceID = NULL,
mbedAustin 26:2896fbdd0450 390 const char * url = NULL,
mbedAustin 26:2896fbdd0450 391 uint8_t urlLen = 0,
mbedAustin 26:2896fbdd0450 392 uint8_t tlmVersion = 0) :
mbedAustin 26:2896fbdd0450 393 ble(bleIn)
mbedAustin 27:29c6d1bb462e 394 {
mbedAustin 26:2896fbdd0450 395 uint8_t serviceData[SERVICE_DATA_MAX];
mbedAustin 26:2896fbdd0450 396 unsigned serviceDataLen = 0;
mbedAustin 26:2896fbdd0450 397 ERR("This function is not fully implemented yet, dont use it!!");
mbedAustin 26:2896fbdd0450 398 // Check optional frames, set their 'isSet' flags appropriately
mbedAustin 26:2896fbdd0450 399 if((uidNamespaceID != NULL) & (uidInstanceID != NULL)) {
mbedAustin 26:2896fbdd0450 400 uidIsSet = true;
mbedAustin 26:2896fbdd0450 401 setUIDFrameData(txPowerLevel,uidNamespaceID, uidInstanceID);
mbedAustin 26:2896fbdd0450 402 } else {
mbedAustin 26:2896fbdd0450 403 uidIsSet = false;
mbedAustin 26:2896fbdd0450 404 }
mbedAustin 26:2896fbdd0450 405 if(url != NULL) {
mbedAustin 26:2896fbdd0450 406 urlIsSet = true;
mbedAustin 26:2896fbdd0450 407 setURLFrameData(txPowerLevel,url);
mbedAustin 26:2896fbdd0450 408 } else {
mbedAustin 26:2896fbdd0450 409 uidIsSet = false;
mbedAustin 26:2896fbdd0450 410 }
mbedAustin 26:2896fbdd0450 411 // Default TLM frame to version 0x00, start all values at zero to be spec compliant.
mbedAustin 26:2896fbdd0450 412 setTLMFrameData(tlmVersion, 0x00,0x00);
mbedAustin 26:2896fbdd0450 413
mbedAustin 26:2896fbdd0450 414 // Initialize Frame transition
mbedAustin 26:2896fbdd0450 415 frameIndex = 0;
mbedAustin 26:2896fbdd0450 416 uidRFU = 0;
mbedAustin 26:2896fbdd0450 417 switchFlag = true;
mbedAustin 26:2896fbdd0450 418
mbedAustin 26:2896fbdd0450 419 /* Reinitialize the BLE stack. This will clear away the existing services and advertising state. */
mbedAustin 26:2896fbdd0450 420 ble.shutdown();
mbedAustin 26:2896fbdd0450 421 ble.init();
mbedAustin 26:2896fbdd0450 422 ble.setTxPower(txPowerLevel);
mbedAustin 26:2896fbdd0450 423 ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
mbedAustin 26:2896fbdd0450 424 ble.setAdvertisingInterval(beaconPeriodus);
mbedAustin 26:2896fbdd0450 425
mbedAustin 26:2896fbdd0450 426 // Make double sure the PDUCount and TimeSinceBoot fields are set to zero at reset
mbedAustin 26:2896fbdd0450 427 updateTlmPduCount(0);
mbedAustin 26:2896fbdd0450 428 updateTlmTimeSinceBoot(0);
mbedAustin 26:2896fbdd0450 429
mbedAustin 26:2896fbdd0450 430 // Construct TLM Frame in initial advertising.
mbedAustin 26:2896fbdd0450 431 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0];
mbedAustin 26:2896fbdd0450 432 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1];
mbedAustin 26:2896fbdd0450 433 serviceDataLen += constructTLMFrame(serviceData+serviceDataLen,SERVICE_DATA_MAX);
mbedAustin 26:2896fbdd0450 434
mbedAustin 26:2896fbdd0450 435 updateAdvPacket(serviceData, serviceDataLen);
mbedAustin 26:2896fbdd0450 436 ble.gap().startAdvertising();
mbedAustin 28:af37cebcb583 437 ble.gap().onRadioNotification(this,&EddystoneService::radioNotificationCallback);
mbedAustin 28:af37cebcb583 438 timeSinceBootTick.attach(this,&EddystoneService::tsbCallback,0.1); // incriment the TimeSinceBoot ticker every 0.1s
mbedAustin 26:2896fbdd0450 439
mbedAustin 26:2896fbdd0450 440 }
mbedAustin 26:2896fbdd0450 441
mbedAustin 26:2896fbdd0450 442 private:
mbedAustin 26:2896fbdd0450 443
mbedAustin 26:2896fbdd0450 444
mbedAustin 26:2896fbdd0450 445 BLEDevice &ble;
mbedAustin 26:2896fbdd0450 446 Ticker timeSinceBootTick;
mbedAustin 26:2896fbdd0450 447 Timeout switchFrame;
mbedAustin 26:2896fbdd0450 448 // Default value that is restored on reset
mbedAustin 26:2896fbdd0450 449 size_t defaultUriDataLength;
mbedAustin 26:2896fbdd0450 450 UriData_t defaultUriData;
mbedAustin 26:2896fbdd0450 451 UIDNamespaceID_t defaultUidNamespaceID;
mbedAustin 26:2896fbdd0450 452 UIDInstanceID_t defaultUidInstanceID;
mbedAustin 26:2896fbdd0450 453 int8_t defaultUidPower;
mbedAustin 26:2896fbdd0450 454 int8_t defaultUrlPower;
mbedAustin 26:2896fbdd0450 455 uint16_t uidRFU;
mbedAustin 26:2896fbdd0450 456 bool uidIsSet;
mbedAustin 26:2896fbdd0450 457 bool urlIsSet;
mbedAustin 26:2896fbdd0450 458 bool switchFlag;
mbedAustin 26:2896fbdd0450 459
mbedAustin 26:2896fbdd0450 460 // Private Variables for Telemetry Data
mbedAustin 26:2896fbdd0450 461 uint8_t TlmVersion;
mbedAustin 26:2896fbdd0450 462 volatile uint16_t TlmBatteryVoltage;
mbedAustin 26:2896fbdd0450 463 volatile uint16_t TlmBeaconTemp;
mbedAustin 26:2896fbdd0450 464 volatile uint32_t TlmPduCount;
mbedAustin 26:2896fbdd0450 465 volatile uint32_t TlmTimeSinceBoot;
mbedAustin 26:2896fbdd0450 466
mbedAustin 26:2896fbdd0450 467 public:
mbedAustin 26:2896fbdd0450 468 /*
mbedAustin 26:2896fbdd0450 469 * Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
mbedAustin 26:2896fbdd0450 470 */
mbedAustin 29:dfb7fb5a971b 471 static void encodeURL(const char *uriDataIn, UriData_t uriDataOut, size_t &sizeofURIDataOut) {
mbedAustin 26:2896fbdd0450 472 const char *prefixes[] = {
mbedAustin 26:2896fbdd0450 473 "http://www.",
mbedAustin 26:2896fbdd0450 474 "https://www.",
mbedAustin 26:2896fbdd0450 475 "http://",
mbedAustin 26:2896fbdd0450 476 "https://",
mbedAustin 26:2896fbdd0450 477 };
mbedAustin 26:2896fbdd0450 478 const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
mbedAustin 26:2896fbdd0450 479 const char *suffixes[] = {
mbedAustin 26:2896fbdd0450 480 ".com/",
mbedAustin 26:2896fbdd0450 481 ".org/",
mbedAustin 26:2896fbdd0450 482 ".edu/",
mbedAustin 26:2896fbdd0450 483 ".net/",
mbedAustin 26:2896fbdd0450 484 ".info/",
mbedAustin 26:2896fbdd0450 485 ".biz/",
mbedAustin 26:2896fbdd0450 486 ".gov/",
mbedAustin 26:2896fbdd0450 487 ".com",
mbedAustin 26:2896fbdd0450 488 ".org",
mbedAustin 26:2896fbdd0450 489 ".edu",
mbedAustin 26:2896fbdd0450 490 ".net",
mbedAustin 26:2896fbdd0450 491 ".info",
mbedAustin 26:2896fbdd0450 492 ".biz",
mbedAustin 26:2896fbdd0450 493 ".gov"
mbedAustin 26:2896fbdd0450 494 };
mbedAustin 26:2896fbdd0450 495 const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
mbedAustin 26:2896fbdd0450 496
mbedAustin 26:2896fbdd0450 497 sizeofURIDataOut = 0;
mbedAustin 26:2896fbdd0450 498 memset(uriDataOut, 0, sizeof(UriData_t));
mbedAustin 26:2896fbdd0450 499
mbedAustin 26:2896fbdd0450 500 if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
mbedAustin 26:2896fbdd0450 501 return;
mbedAustin 26:2896fbdd0450 502 }
mbedAustin 26:2896fbdd0450 503
mbedAustin 26:2896fbdd0450 504 /*
mbedAustin 26:2896fbdd0450 505 * handle prefix
mbedAustin 26:2896fbdd0450 506 */
mbedAustin 26:2896fbdd0450 507 for (unsigned i = 0; i < NUM_PREFIXES; i++) {
mbedAustin 26:2896fbdd0450 508 size_t prefixLen = strlen(prefixes[i]);
mbedAustin 26:2896fbdd0450 509 if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
mbedAustin 26:2896fbdd0450 510 uriDataOut[sizeofURIDataOut++] = i;
mbedAustin 26:2896fbdd0450 511 uriDataIn += prefixLen;
mbedAustin 26:2896fbdd0450 512 break;
mbedAustin 26:2896fbdd0450 513 }
mbedAustin 26:2896fbdd0450 514 }
mbedAustin 26:2896fbdd0450 515
mbedAustin 26:2896fbdd0450 516 /*
mbedAustin 26:2896fbdd0450 517 * handle suffixes
mbedAustin 26:2896fbdd0450 518 */
mbedAustin 26:2896fbdd0450 519 while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
mbedAustin 26:2896fbdd0450 520 /* check for suffix match */
mbedAustin 26:2896fbdd0450 521 unsigned i;
mbedAustin 26:2896fbdd0450 522 for (i = 0; i < NUM_SUFFIXES; i++) {
mbedAustin 26:2896fbdd0450 523 size_t suffixLen = strlen(suffixes[i]);
mbedAustin 26:2896fbdd0450 524 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
mbedAustin 26:2896fbdd0450 525 uriDataOut[sizeofURIDataOut++] = i;
mbedAustin 26:2896fbdd0450 526 uriDataIn += suffixLen;
mbedAustin 26:2896fbdd0450 527 break; /* from the for loop for checking against suffixes */
mbedAustin 26:2896fbdd0450 528 }
mbedAustin 26:2896fbdd0450 529 }
mbedAustin 26:2896fbdd0450 530 /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
mbedAustin 26:2896fbdd0450 531 if (i == NUM_SUFFIXES) {
mbedAustin 26:2896fbdd0450 532 uriDataOut[sizeofURIDataOut++] = *uriDataIn;
mbedAustin 26:2896fbdd0450 533 ++uriDataIn;
mbedAustin 26:2896fbdd0450 534 }
mbedAustin 26:2896fbdd0450 535 }
mbedAustin 26:2896fbdd0450 536 }
mbedAustin 26:2896fbdd0450 537 };
mbedAustin 26:2896fbdd0450 538
mbedAustin 26:2896fbdd0450 539 #endif // SERVICES_EDDYSTONEBEACON_H_