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