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

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.