adaptation for book and plug demo

Dependents:   BookAndPlug

Fork of BLE_API by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EddystoneService.h Source File

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_