Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of LinkNode-Test by
EddystoneService.h
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2015 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #ifndef SERVICES_EDDYSTONEBEACON_H_ 00018 #define SERVICES_EDDYSTONEBEACON_H_ 00019 00020 #warning ble/services/EddystoneService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'. 00021 00022 #include "ble/BLE.h" 00023 #include "mbed.h" 00024 #include "CircularBuffer.h" 00025 static const uint8_t BEACON_EDDYSTONE[] = {0xAA, 0xFE}; 00026 00027 //Debug is disabled by default 00028 #if 0 00029 #define DBG(MSG, ...) printf("[EddyStone: DBG]" MSG " \t[%s,%d]\r\n", \ 00030 ## __VA_ARGS__, \ 00031 __FILE__, \ 00032 __LINE__); 00033 #define WARN(MSG, ...) printf("[EddyStone: WARN]" MSG " \t[%s,%d]\r\n", \ 00034 ## __VA_ARGS__, \ 00035 __FILE__, \ 00036 __LINE__); 00037 #define ERR(MSG, ...) printf("[EddyStone: ERR]" MSG " \t[%s,%d]\r\n", \ 00038 ## __VA_ARGS__, \ 00039 __FILE__, \ 00040 __LINE__); 00041 #else // if 0 00042 #define DBG(x, ...) //wait_us(10); 00043 #define WARN(x, ...) //wait_us(10); 00044 #define ERR(x, ...) 00045 #endif // if 0 00046 00047 #if 0 00048 #define INFO(x, ...) printf("[EddyStone: INFO]"x " \t[%s,%d]\r\n", \ 00049 ## __VA_ARGS__, \ 00050 __FILE__, \ 00051 __LINE__); 00052 #else // if 0 00053 #define INFO(x, ...) 00054 #endif // if 0 00055 00056 /** 00057 * @class Eddystone 00058 * @brief Eddystone Configuration Service. Can be used to set URL, adjust power levels, and set flags. 00059 * See https://github.com/google/eddystone 00060 * 00061 */ 00062 class EddystoneService 00063 { 00064 public: 00065 enum FrameTypes { 00066 NONE, 00067 url, 00068 uid, 00069 tlm 00070 }; 00071 00072 static const int SERVICE_DATA_MAX = 31; // Maximum size of service data in ADV packets 00073 00074 // There are currently 3 subframes defined, URI, UID, and TLM 00075 #define EDDYSTONE_MAX_FRAMETYPE 3 00076 void (*frames[EDDYSTONE_MAX_FRAMETYPE])(uint8_t *, uint32_t); 00077 static const int URI_DATA_MAX = 18; 00078 typedef uint8_t UriData_t[URI_DATA_MAX]; 00079 CircularBuffer<FrameTypes, EDDYSTONE_MAX_FRAMETYPE> overflow; 00080 00081 // UID Frame Type subfields 00082 static const int UID_NAMESPACEID_SIZE = 10; 00083 typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE]; 00084 static const int UID_INSTANCEID_SIZE = 6; 00085 typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE]; 00086 00087 // Eddystone Frame Type ID 00088 static const uint8_t FRAME_TYPE_UID = 0x00; 00089 static const uint8_t FRAME_TYPE_URL = 0x10; 00090 static const uint8_t FRAME_TYPE_TLM = 0x20; 00091 00092 static const uint8_t FRAME_SIZE_TLM = 14; // TLM frame is a constant 14Bytes 00093 static const uint8_t FRAME_SIZE_UID = 20; // includes RFU bytes 00094 00095 /** 00096 * Set Eddystone UID Frame information. 00097 * 00098 * @param[in] power TX Power in dB measured at 0 meters from the device. Range of -100 to +20 dB. 00099 * @param[in] namespaceID 10B namespace ID 00100 * @param[in] instanceID 6B instance ID 00101 * @param[in] RFU 2B of RFU, initialized to 0x0000 and not broadcast, included for future reference. 00102 */ 00103 void setUIDFrameData(int8_t power, 00104 UIDNamespaceID_t namespaceID, 00105 UIDInstanceID_t instanceID, 00106 float uidAdvPeriodIn, 00107 uint16_t RFU = 0x0000) { 00108 if (0.0f == uidAdvPeriodIn) { 00109 uidIsSet = false; 00110 return; 00111 } 00112 if (power > 20) { 00113 power = 20; 00114 } 00115 if (power < -100) { 00116 power = -100; 00117 } 00118 00119 defaultUidPower = power; 00120 memcpy(defaultUidNamespaceID, namespaceID, UID_NAMESPACEID_SIZE); 00121 memcpy(defaultUidInstanceID, instanceID, UID_INSTANCEID_SIZE); 00122 uidRFU = (uint16_t)RFU; // this is probably bad form, but it doesn't really matter yet. 00123 uidAdvPeriod = uidAdvPeriodIn; 00124 uidIsSet = true; // set toggle to advertise UID frames 00125 } 00126 00127 /* 00128 * Construct UID frame from private variables 00129 * @param[in/out] Data pointer to array to store constructed frame in 00130 * @param[in] maxSize number of bytes left in array, effectively how much empty space is available to write to 00131 * @return number of bytes used. negative number indicates error message. 00132 */ 00133 unsigned constructUIDFrame(uint8_t *Data, uint8_t maxSize) { 00134 unsigned index = 0; 00135 00136 Data[index++] = FRAME_TYPE_UID; // 1B Type 00137 00138 if (defaultUidPower > 20) { 00139 defaultUidPower = 20; // enforce range of vaild values. 00140 } 00141 if (defaultUidPower < -100) { 00142 defaultUidPower = -100; 00143 } 00144 Data[index++] = defaultUidPower; // 1B Power @ 0meter 00145 00146 DBG("UID NamespaceID = '0x"); 00147 for (size_t x = 0; x < UID_NAMESPACEID_SIZE; x++) { // 10B Namespace ID 00148 Data[index++] = defaultUidNamespaceID[x]; 00149 DBG("%x,", defaultUidNamespaceID[x]); 00150 } 00151 DBG("'\r\n"); 00152 00153 DBG("UID InstanceID = '0x"); 00154 for (size_t x = 0; x< UID_INSTANCEID_SIZE; x++) { // 6B Instance ID 00155 Data[index++] = defaultUidInstanceID[x]; 00156 DBG("%x,", defaultUidInstanceID[x]); 00157 } 00158 DBG("'\r\n"); 00159 00160 if (0 != uidRFU) { // 2B RFU, include if non-zero, otherwise ignore 00161 Data[index++] = (uint8_t)(uidRFU >> 0); 00162 Data[index++] = (uint8_t)(uidRFU >> 8); 00163 } 00164 DBG("construcUIDFrame %d, %d", maxSize, index); 00165 return index; 00166 } 00167 00168 /** 00169 * Set Eddystone URL Frame information. 00170 * @param[in] power TX Power in dB measured at 0 meters from the device. 00171 * @param[in] url URL to encode 00172 * @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods) 00173 * @return false on success, true on failure. 00174 */ 00175 bool setURLFrameData(int8_t power, const char *urlIn, float urlAdvPeriodIn) { 00176 if (0.0f == urlAdvPeriodIn) { 00177 urlIsSet = false; 00178 return false; 00179 } 00180 encodeURL(urlIn, defaultUriData, defaultUriDataLength); // encode URL to URL Formatting 00181 if (defaultUriDataLength > URI_DATA_MAX) { 00182 return true; // error, URL is too big 00183 } 00184 defaultUrlPower = power; 00185 urlAdvPeriod = urlAdvPeriodIn; 00186 urlIsSet = true; 00187 return false; 00188 } 00189 00190 /** 00191 * Set Eddystone URL Frame information. 00192 * @param[in] power TX Power in dB measured at 0 meters from the device. 00193 * @param[in] encodedUrlIn Encoded URL 00194 * @param[in] encodedUrlInLength Length of the encoded URL 00195 * @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods) 00196 * @return false on success, true on failure. 00197 */ 00198 bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, float urlAdvPeriodIn) { 00199 if (0.0f == urlAdvPeriodIn) { 00200 urlIsSet = false; 00201 return false; 00202 } 00203 memcpy(defaultUriData, encodedUrlIn, encodedUrlInLength); 00204 if (defaultUriDataLength > URI_DATA_MAX) { 00205 return true; // error, URL is too big 00206 } 00207 defaultUrlPower = power; 00208 defaultUriDataLength = encodedUrlInLength; 00209 urlAdvPeriod = urlAdvPeriodIn; 00210 urlIsSet = true; 00211 return false; 00212 } 00213 00214 /* 00215 * Construct URL frame from private variables 00216 * @param[in/out] Data pointer to array to store constructed frame in 00217 * @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to 00218 * @return number of bytes used. negative number indicates error message. 00219 */ 00220 int constructURLFrame(uint8_t *Data, uint8_t maxSize) { 00221 int index = 0; 00222 Data[index++] = FRAME_TYPE_URL; // 1B Type 00223 Data[index++] = defaultUrlPower; // 1B TX Power 00224 for (int x = 0; x < defaultUriDataLength; x++) { // 18B of URL Prefix + encoded URL 00225 Data[index++] = defaultUriData[x]; 00226 } 00227 DBG("constructURLFrame: %d, %d", maxSize, index); 00228 return index; 00229 } 00230 00231 /* 00232 * Set Eddystone TLM Frame information. 00233 * @param[in] Version of the TLM beacon data format 00234 * @param[in] advPeriod how often to advertise the TLM frame for (in minutes) 00235 * @param batteryVoltage in milivolts 00236 * @param beaconTemp in 8.8 floating point notation 00237 * 00238 */ 00239 void setTLMFrameData(uint8_t version = 0, 00240 float advPeriod = 60.0f, 00241 uint16_t batteryVoltage = 0, 00242 uint16_t beaconTemp = 0x8000, 00243 uint32_t pduCount = 0, 00244 uint32_t timeSinceBoot = 0) { 00245 if (0.0f == advPeriod) { 00246 tlmIsSet = false; 00247 return; 00248 } 00249 TlmVersion = version; 00250 TlmBatteryVoltage = batteryVoltage; 00251 TlmBeaconTemp = beaconTemp; 00252 TlmPduCount = pduCount; // reset 00253 TlmTimeSinceBoot = timeSinceBoot; // reset 00254 TlmAdvPeriod = advPeriod; 00255 tlmIsSet = true; // TLM Data has been enabled 00256 } 00257 00258 /* 00259 * Construct TLM frame from private variables 00260 * @param[in/out] Data pointer to array to store constructed frame in 00261 * @param[in] maxSize number of bytes left in array, effectively how much emtpy space is available to write to 00262 * @return number of bytes used. negative number indicates error message. 00263 */ 00264 int constructTLMFrame(uint8_t *Data, uint8_t maxSize) { 00265 uint32_t now = timeSinceBootTimer.read_ms(); 00266 TlmTimeSinceBoot += (now - lastBootTimerRead) / 100; 00267 lastBootTimerRead = now; 00268 00269 int index = 0; 00270 Data[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry 00271 Data[index++] = TlmVersion; // TLM Version Number 00272 Data[index++] = (uint8_t)(TlmBatteryVoltage >> 8); // Battery Voltage[0] 00273 Data[index++] = (uint8_t)(TlmBatteryVoltage >> 0); // Battery Voltage[1] 00274 Data[index++] = (uint8_t)(TlmBeaconTemp >> 8); // Beacon Temp[0] 00275 Data[index++] = (uint8_t)(TlmBeaconTemp >> 0); // Beacon Temp[1] 00276 Data[index++] = (uint8_t)(TlmPduCount >> 24); // PDU Count [0] 00277 Data[index++] = (uint8_t)(TlmPduCount >> 16); // PDU Count [1] 00278 Data[index++] = (uint8_t)(TlmPduCount >> 8); // PDU Count [2] 00279 Data[index++] = (uint8_t)(TlmPduCount >> 0); // PDU Count [3] 00280 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 24); // Time Since Boot [0] 00281 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 16); // Time Since Boot [1] 00282 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 8); // Time Since Boot [2] 00283 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 0); // Time Since Boot [3] 00284 DBG("constructURLFrame: %d, %d", maxSize, index); 00285 return index; 00286 } 00287 00288 /* 00289 * Update the TLM frame battery voltage value 00290 * @param[in] voltagemv Voltage to update the TLM field battery voltage with (in mV) 00291 * @return nothing 00292 */ 00293 void updateTlmBatteryVoltage(uint16_t voltagemv) { 00294 TlmBatteryVoltage = voltagemv; 00295 } 00296 00297 /* 00298 * Update the TLM frame beacon temperature 00299 * @param[in] temp Temperature of beacon (in 8.8fpn) 00300 * @return nothing 00301 */ 00302 void updateTlmBeaconTemp(uint16_t temp) { 00303 TlmBeaconTemp = temp; 00304 } 00305 00306 /* 00307 * Update the TLM frame PDU Count field 00308 * @param[in] pduCount Number of Advertisiting frames sent since powerup 00309 * @return nothing 00310 */ 00311 void updateTlmPduCount(uint32_t pduCount) { 00312 TlmPduCount = pduCount; 00313 } 00314 00315 /* 00316 * Update the TLM frame Time since boot in 0.1s incriments 00317 * @param[in] timeSinceBoot Time since boot in 0.1s incriments 00318 * @return nothing 00319 */ 00320 void updateTlmTimeSinceBoot(uint32_t timeSinceBoot) { 00321 TlmTimeSinceBoot = timeSinceBoot; 00322 } 00323 00324 /* 00325 * Update advertising data 00326 * @return true on success, false on failure 00327 */ 00328 bool updateAdvPacket(uint8_t serviceData[], unsigned serviceDataLen) { 00329 // Fields from the Service 00330 DBG("Updating AdvFrame: %d", serviceDataLen); 00331 00332 ble.clearAdvertisingPayload(); 00333 ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED); 00334 ble.setAdvertisingInterval (100); 00335 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00336 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_EDDYSTONE, sizeof(BEACON_EDDYSTONE)); 00337 ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen); 00338 00339 00340 return true; 00341 } 00342 00343 /* 00344 * State machine for switching out frames. 00345 * This function is called by the radioNotificationCallback when a frame needs to get swapped out. 00346 * This function exists because of time constraints in the radioNotificationCallback, so it is effectively 00347 * broken up into two functions. 00348 */ 00349 void swapOutFrames(FrameTypes frameType) { 00350 uint8_t serviceData[SERVICE_DATA_MAX]; 00351 unsigned serviceDataLen = 0; 00352 //hard code in the eddystone UUID 00353 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0]; 00354 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1]; 00355 00356 // if certain frames are not enabled, then skip them. Worst case TLM is always enabled 00357 switch (frameType) { 00358 case tlm: 00359 // TLM frame 00360 if (tlmIsSet) { 00361 DBG("Swapping in TLM Frame: version=%x, Batt=%d, Temp = %d, PDUCnt = %d, TimeSinceBoot=%d", 00362 TlmVersion, 00363 TlmBatteryVoltage, 00364 TlmBeaconTemp, 00365 TlmPduCount, 00366 TlmTimeSinceBoot); 00367 serviceDataLen += constructTLMFrame(serviceData + serviceDataLen, 20); 00368 DBG("\t Swapping in TLM Frame: len=%d", serviceDataLen); 00369 updateAdvPacket(serviceData, serviceDataLen); 00370 } 00371 break; 00372 case url: 00373 // URL Frame 00374 if (urlIsSet) { 00375 DBG("Swapping in URL Frame: Power: %d", defaultUrlPower); 00376 serviceDataLen += constructURLFrame(serviceData + serviceDataLen, 20); 00377 DBG("\t Swapping in URL Frame: len=%d ", serviceDataLen); 00378 updateAdvPacket(serviceData, serviceDataLen); 00379 //switchFlag = false; 00380 } 00381 break; 00382 case uid: 00383 // UID Frame 00384 if (uidIsSet) { 00385 DBG("Swapping in UID Frame: Power: %d", defaultUidPower); 00386 serviceDataLen += constructUIDFrame(serviceData + serviceDataLen, 20); 00387 DBG("\t Swapping in UID Frame: len=%d", serviceDataLen); 00388 updateAdvPacket(serviceData, serviceDataLen); 00389 //switchFlag = false; 00390 } 00391 break; 00392 default: 00393 ERR("You have not initialized a Frame yet, please initialize one before starting a beacon"); 00394 ERR("uidIsSet = %d, urlIsSet = %d, tlmIsSet = %d", uidIsSet, urlIsSet, tlmIsSet); 00395 } 00396 } 00397 00398 /* 00399 * Callback to swap in URL frame 00400 */ 00401 void urlCallback(void) { 00402 DBG("urlCallback"); 00403 if (false == advLock) { 00404 advLock = true; 00405 DBG("advLock = url") 00406 frameIndex = url; 00407 swapOutFrames(frameIndex); 00408 ble.startAdvertising(); 00409 } else { 00410 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free 00411 INFO("URI(%d) cannot complete, %d is currently broadcasting", url, frameIndex); 00412 FrameTypes x = url; 00413 overflow.push(x); 00414 } 00415 } 00416 00417 /* 00418 * Callback to swap in UID frame 00419 */ 00420 void uidCallback(void) { 00421 DBG("uidCallback"); 00422 if (false == advLock) { 00423 advLock = true; 00424 DBG("advLock = uid") 00425 frameIndex = uid; 00426 swapOutFrames(frameIndex); 00427 ble.startAdvertising(); 00428 } else { 00429 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free 00430 INFO("UID(%d) cannot complete, %d is currently broadcasting", uid, frameIndex); 00431 FrameTypes x = uid; // have to do this to satisfy cont vs volatile keywords... sigh... 00432 overflow.push(x); 00433 } 00434 } 00435 00436 /* 00437 * Callback to swap in TLM frame 00438 */ 00439 void tlmCallback(void) { 00440 DBG("tlmCallback"); 00441 if (false == advLock) { 00442 // OK to broadcast 00443 advLock = true; 00444 DBG("advLock = tlm") 00445 frameIndex = tlm; 00446 swapOutFrames(frameIndex); 00447 ble.startAdvertising(); 00448 } else { 00449 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free 00450 INFO("TLM(%d) cannot complete, %d is currently broadcasting", tlm, frameIndex); 00451 FrameTypes x = tlm; 00452 overflow.push(x); 00453 } 00454 } 00455 00456 void stopAdvCallback(void) { 00457 if (overflow.empty()) { 00458 // if nothing left to transmit, stop 00459 ble.stopAdvertising(); 00460 advLock = false; // unlock lock 00461 } else { 00462 // transmit other packets at current time index 00463 FrameTypes x = NONE; 00464 overflow.pop(x); 00465 INFO("Re-Transmitting %d", x); 00466 swapOutFrames(x); 00467 } 00468 } 00469 00470 /* 00471 * Callback from onRadioNotification(), used to update the PDUCounter and process next state. 00472 */ 00473 #define EDDYSTONE_SWAPFRAME_DELAYMS 1 00474 void radioNotificationCallback(bool radioActive) { 00475 // Update PDUCount 00476 TlmPduCount++; 00477 // True just before an frame is sent, false just after a frame is sent 00478 if (radioActive) { 00479 // Do Nothing 00480 } else { 00481 // Packet has been sent, disable advertising 00482 stopAdv.attach_us(this, &EddystoneService::stopAdvCallback, 1); 00483 } 00484 } 00485 00486 /* 00487 * This function explicityly sets the parameters used by the Eddystone beacon. 00488 * this function should be used in leu of the config service. 00489 * 00490 * @param bleIn ble object used to broadcast eddystone information 00491 * @param beaconPeriodus is how often ble broadcasts are mde, in mili seconds 00492 * @param txPowerLevel sets the broadcasting power level. 00493 * 00494 */ 00495 EddystoneService(BLEDevice &bleIn, 00496 uint16_t beaconPeriodus = 100, 00497 uint8_t txPowerIn = 0) : 00498 ble(bleIn), 00499 advPeriodus(beaconPeriodus), 00500 txPower(txPowerIn), 00501 advLock(false), 00502 frameIndex(NONE) { 00503 } 00504 00505 /* 00506 * @breif this function starts eddystone advertising based on configured frames. 00507 */ 00508 void start(void) { 00509 // Initialize Frame transition, start with URL to pass eddystone validator app on first try 00510 if (urlIsSet) { 00511 frameIndex = url; 00512 urlTicker.attach(this, &EddystoneService::urlCallback, (float) advPeriodus / 1000.0f); 00513 DBG("attached urlCallback every %d seconds", urlAdvPeriod); 00514 } 00515 if (uidIsSet) { 00516 frameIndex = uid; 00517 uidTicker.attach(this, &EddystoneService::uidCallback, uidAdvPeriod); 00518 DBG("attached uidCallback every %d seconds", uidAdvPeriod); 00519 } 00520 if (tlmIsSet) { 00521 frameIndex = tlm; 00522 // Make double sure the PDUCount and TimeSinceBoot fields are set to zero at reset 00523 updateTlmPduCount(0); 00524 updateTlmTimeSinceBoot(0); 00525 lastBootTimerRead = 0; 00526 timeSinceBootTimer.start(); 00527 tlmTicker.attach(this, &EddystoneService::tlmCallback, TlmAdvPeriod); 00528 DBG("attached tlmCallback every %d seconds", TlmAdvPeriod); 00529 } 00530 if (NONE == frameIndex) { 00531 error("No Frames were Initialized! Please initialize a frame before starting an eddystone beacon."); 00532 } 00533 //uidRFU = 0; 00534 00535 ble.setTxPower(txPower); 00536 ble.gap().onRadioNotification(this, &EddystoneService::radioNotificationCallback); 00537 } 00538 00539 private: 00540 00541 // Eddystone Variables 00542 BLEDevice &ble; 00543 uint16_t advPeriodus; 00544 uint8_t txPower; 00545 Timer timeSinceBootTimer; 00546 volatile uint32_t lastBootTimerRead; 00547 volatile bool advLock; 00548 volatile FrameTypes frameIndex; 00549 Timeout stopAdv; 00550 00551 00552 // URI Frame Variables 00553 uint8_t defaultUriDataLength; 00554 UriData_t defaultUriData; 00555 int8_t defaultUrlPower; 00556 bool urlIsSet; // flag that enables / disable URI Frames 00557 float urlAdvPeriod; // how long the url frame will be advertised for 00558 Ticker urlTicker; 00559 00560 // UID Frame Variables 00561 UIDNamespaceID_t defaultUidNamespaceID; 00562 UIDInstanceID_t defaultUidInstanceID; 00563 int8_t defaultUidPower; 00564 uint16_t uidRFU; 00565 bool uidIsSet; // flag that enables / disable UID Frames 00566 float uidAdvPeriod; // how long the uid frame will be advertised for 00567 Ticker uidTicker; 00568 00569 // TLM Frame Variables 00570 uint8_t TlmVersion; 00571 volatile uint16_t TlmBatteryVoltage; 00572 volatile uint16_t TlmBeaconTemp; 00573 volatile uint32_t TlmPduCount; 00574 volatile uint32_t TlmTimeSinceBoot; 00575 bool tlmIsSet; // flag that enables / disables TLM frames 00576 float TlmAdvPeriod; // number of minutes between adv frames 00577 Ticker tlmTicker; 00578 00579 public: 00580 /* 00581 * Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification). 00582 */ 00583 static void encodeURL(const char *uriDataIn, UriData_t uriDataOut, uint8_t &sizeofURIDataOut) { 00584 DBG("Encode URL = %s", uriDataIn); 00585 const char *prefixes[] = { 00586 "http://www.", 00587 "https://www.", 00588 "http://", 00589 "https://", 00590 }; 00591 const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *); 00592 const char *suffixes[] = { 00593 ".com/", 00594 ".org/", 00595 ".edu/", 00596 ".net/", 00597 ".info/", 00598 ".biz/", 00599 ".gov/", 00600 ".com", 00601 ".org", 00602 ".edu", 00603 ".net", 00604 ".info", 00605 ".biz", 00606 ".gov" 00607 }; 00608 const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *); 00609 00610 sizeofURIDataOut = 0; 00611 memset(uriDataOut, 0, sizeof(UriData_t)); 00612 00613 if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) { 00614 return; 00615 } 00616 00617 /* 00618 * handle prefix 00619 */ 00620 for (unsigned i = 0; i < NUM_PREFIXES; i++) { 00621 size_t prefixLen = strlen(prefixes[i]); 00622 if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) { 00623 uriDataOut[sizeofURIDataOut++] = i; 00624 uriDataIn += prefixLen; 00625 break; 00626 } 00627 } 00628 00629 /* 00630 * handle suffixes 00631 */ 00632 while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) { 00633 /* check for suffix match */ 00634 unsigned i; 00635 for (i = 0; i < NUM_SUFFIXES; i++) { 00636 size_t suffixLen = strlen(suffixes[i]); 00637 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) { 00638 uriDataOut[sizeofURIDataOut++] = i; 00639 uriDataIn += suffixLen; 00640 break; /* from the for loop for checking against suffixes */ 00641 } 00642 } 00643 /* This is the default case where we've got an ordinary character which doesn't match a suffix. */ 00644 INFO("Encoding URI: No Suffix Found"); 00645 if (i == NUM_SUFFIXES) { 00646 uriDataOut[sizeofURIDataOut++] = *uriDataIn; 00647 ++uriDataIn; 00648 } 00649 } 00650 } 00651 }; 00652 00653 #endif // SERVICES_EDDYSTONEBEACON_H_
Generated on Tue Jul 12 2022 16:00:20 by
