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:04 2015 +0000
Revision:
918:2b12b53101ea
Synchronized with git rev 162fb4f7
Author: Vincent Coubard
Add detach operation to CallChainOfFunctionPointersWithContext, Add
operator== to functionpointerWithContext class

Who changed what in which revision?

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