High level Bluetooth Low Energy API and radio abstraction layer

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Wed Dec 02 10:29:44 2015 +0000
Revision:
993:4d62b7967c11
Parent:
992:ca834f7ae8ed
Child:
1042:21a86ac7f5b1
Synchronized with git rev 12e27cd4
Author: Rohit Grover
Release 2.1.3
=============

* Improvements to CallChainOfFunctionPointerswithContext:
- add a `detach` function to be able to remove callbacks.
- detach function now return true if a function has been detached and
false otherwise.
- add a function call operator.
- use safe-bool idiom. see : http://www.artima.com/cppsource/safebool.html

* Add SafeBool class which allow to easily declare a safe bool operator in
c++03.

* Improvements to FunctionPointerWithContext:
- fix call propagation
- use safe bool idiom

* Add config file for generating Doxygen.

* Setup for onRadioNotification callback does not call initRadioNotification
anymore.

* GapAdvertisementData now handles replacement and appending of data fields
based on type. Some fields can be replaced with new values, and others
require the payload to be appended.

Who changed what in which revision?

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