aa

Dependents:   Peripheral_1_serial_copy Peripheral_1_serial 151006_1st_Scenario_normal

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Tue Sep 29 09:54:18 2015 +0100
Revision:
831:a6ef72e0697a
Parent:
786:d6d7087d8377
Child:
833:5dac246f8f02
Synchronized with git rev 1811f210
Author: Austin Blackstone
updated eddystone service and added config service.

Who changed what in which revision?

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