High level Bluetooth Low Energy API and radio abstraction layer

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Thu Nov 26 12:52:36 2015 +0000
Revision:
978:7d8155c636b8
Child:
992:ca834f7ae8ed
Synchronized with git rev 5c86cb0a
Author: Andres Amaya Garcia
Reintroduce old Eddystone with deprecated warnings

For compatibility reasons in mbed classic, the old Eddystone implementation
under ble/services (i.e. EddystoneConfigService.h and EddystoneService.h) is
reintroduced. However, attempting to use this files with generate a deprecation
warning at compile time with the URL of the ble-example/BLE_EddystoneService.

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 978:7d8155c636b8 20 #warning ble/services/EddystoneService.h is deprecated. Please use the example in 'github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneService'.
rgrover1 978:7d8155c636b8 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_