jgh

Dependents:   Migration

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Mon Nov 02 09:09:06 2015 +0000
Revision:
857:7f578be2d01d
Parent:
851:802f445cc195
Child:
860:0d41e4eb3d0a
Synchronized with git rev 976bcd4e
Author: Andres Amaya Garcia
Introduced fixes to Eddystone implementation

Fixed wrong memcpy arguments that caused the wrong number of bytes to be copied
and merged energy saving changes.

Who changed what in which revision?

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