Lancaster University's fork of the mbed BLE API. Lives on github, https://github.com/lancaster-university/BLE_API

Dependents:   microbit-dal microbit-dal microbit-ble-open microbit-dal ... more

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Mon Nov 02 09:09:04 2015 +0000
Revision:
842:4f7f7a4b0cb2
Parent:
841:468a5863cacb
Child:
850:32ff6e392630
Synchronized with git rev f8e3d2f4
Author: Andres Amaya Garcia
Introduced fixes after review

Introduced fixes after review of previous commit with regards to JIRA defect
IOTSFW-1058.

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 842:4f7f7a4b0cb2 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 841:468a5863cacb 188 /**
rgrover1 841:468a5863cacb 189 * Set Eddystone URL Frame information.
rgrover1 842:4f7f7a4b0cb2 190 * @param[in] power TX Power in dB measured at 0 meters from the device.
rgrover1 842:4f7f7a4b0cb2 191 * @param[in] encodedUrlIn Encoded URL
rgrover1 842:4f7f7a4b0cb2 192 * @param[in] encodedUrlInLength Length of the encoded URL
rgrover1 842:4f7f7a4b0cb2 193 * @param[in] urlAdvPeriodIn How long to advertise the URL frame (measured in # of adv periods)
rgrover1 841:468a5863cacb 194 * @return false on success, true on failure.
rgrover1 841:468a5863cacb 195 */
rgrover1 842:4f7f7a4b0cb2 196 bool setURLFrameEncodedData(int8_t power, const char *encodedUrlIn, uint8_t encodedUrlInLength, uint32_t urlAdvPeriodIn) {
rgrover1 841:468a5863cacb 197 if (0 == urlAdvPeriodIn) {
rgrover1 841:468a5863cacb 198 urlIsSet = false;
rgrover1 841:468a5863cacb 199 return false;
rgrover1 841:468a5863cacb 200 }
rgrover1 842:4f7f7a4b0cb2 201 memcpy(defaultUriData, encodedUrlIn, encodedUrlInLength);
rgrover1 841:468a5863cacb 202 if (defaultUriDataLength > URI_DATA_MAX) {
rgrover1 841:468a5863cacb 203 return true; // error, URL is too big
rgrover1 841:468a5863cacb 204 }
rgrover1 842:4f7f7a4b0cb2 205 defaultUrlPower = power;
rgrover1 842:4f7f7a4b0cb2 206 defaultUriDataLength = encodedUrlInLength;
rgrover1 842:4f7f7a4b0cb2 207 urlAdvPeriod = urlAdvPeriodIn;
rgrover1 842:4f7f7a4b0cb2 208 urlIsSet = true;
rgrover1 841:468a5863cacb 209 return false;
rgrover1 841:468a5863cacb 210 }
rgrover1 841:468a5863cacb 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 786:d6d7087d8377 263 int index = 0;
rgrover1 786:d6d7087d8377 264 Data[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry
rgrover1 786:d6d7087d8377 265 Data[index++] = TlmVersion; // TLM Version Number
rgrover1 832:5dac246f8f02 266 Data[index++] = (uint8_t)(TlmBatteryVoltage >> 8); // Battery Voltage[0]
rgrover1 832:5dac246f8f02 267 Data[index++] = (uint8_t)(TlmBatteryVoltage >> 0); // Battery Voltage[1]
rgrover1 832:5dac246f8f02 268 Data[index++] = (uint8_t)(TlmBeaconTemp >> 8); // Beacon Temp[0]
rgrover1 832:5dac246f8f02 269 Data[index++] = (uint8_t)(TlmBeaconTemp >> 0); // Beacon Temp[1]
rgrover1 832:5dac246f8f02 270 Data[index++] = (uint8_t)(TlmPduCount >> 24); // PDU Count [0]
rgrover1 832:5dac246f8f02 271 Data[index++] = (uint8_t)(TlmPduCount >> 16); // PDU Count [1]
rgrover1 832:5dac246f8f02 272 Data[index++] = (uint8_t)(TlmPduCount >> 8); // PDU Count [2]
rgrover1 832:5dac246f8f02 273 Data[index++] = (uint8_t)(TlmPduCount >> 0); // PDU Count [3]
rgrover1 832:5dac246f8f02 274 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 24); // Time Since Boot [0]
rgrover1 832:5dac246f8f02 275 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 16); // Time Since Boot [1]
rgrover1 832:5dac246f8f02 276 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 8); // Time Since Boot [2]
rgrover1 832:5dac246f8f02 277 Data[index++] = (uint8_t)(TlmTimeSinceBoot >> 0); // Time Since Boot [3]
rgrover1 832:5dac246f8f02 278 DBG("constructURLFrame: %d, %d", maxSize, index);
rgrover1 771:26b809199308 279 return index;
rgrover1 771:26b809199308 280 }
rgrover1 771:26b809199308 281
rgrover1 771:26b809199308 282 /*
rgrover1 786:d6d7087d8377 283 * Update the TLM frame battery voltage value
rgrover1 786:d6d7087d8377 284 * @param[in] voltagemv Voltage to update the TLM field battery voltage with (in mV)
rgrover1 786:d6d7087d8377 285 * @return nothing
rgrover1 786:d6d7087d8377 286 */
rgrover1 786:d6d7087d8377 287 void updateTlmBatteryVoltage(uint16_t voltagemv) {
rgrover1 786:d6d7087d8377 288 TlmBatteryVoltage = voltagemv;
rgrover1 786:d6d7087d8377 289 }
rgrover1 786:d6d7087d8377 290
rgrover1 786:d6d7087d8377 291 /*
rgrover1 786:d6d7087d8377 292 * Update the TLM frame beacon temperature
rgrover1 786:d6d7087d8377 293 * @param[in] temp Temperature of beacon (in 8.8fpn)
rgrover1 786:d6d7087d8377 294 * @return nothing
rgrover1 786:d6d7087d8377 295 */
rgrover1 786:d6d7087d8377 296 void updateTlmBeaconTemp(uint16_t temp) {
rgrover1 786:d6d7087d8377 297 TlmBeaconTemp = temp;
rgrover1 786:d6d7087d8377 298 }
rgrover1 786:d6d7087d8377 299
rgrover1 786:d6d7087d8377 300 /*
rgrover1 786:d6d7087d8377 301 * Update the TLM frame PDU Count field
rgrover1 786:d6d7087d8377 302 * @param[in] pduCount Number of Advertisiting frames sent since powerup
rgrover1 786:d6d7087d8377 303 * @return nothing
rgrover1 786:d6d7087d8377 304 */
rgrover1 786:d6d7087d8377 305 void updateTlmPduCount(uint32_t pduCount) {
rgrover1 786:d6d7087d8377 306 TlmPduCount = pduCount;
rgrover1 771:26b809199308 307 }
rgrover1 771:26b809199308 308
rgrover1 771:26b809199308 309 /*
rgrover1 786:d6d7087d8377 310 * Update the TLM frame Time since boot in 0.1s incriments
rgrover1 786:d6d7087d8377 311 * @param[in] timeSinceBoot Time since boot in 0.1s incriments
rgrover1 786:d6d7087d8377 312 * @return nothing
rgrover1 786:d6d7087d8377 313 */
rgrover1 786:d6d7087d8377 314 void updateTlmTimeSinceBoot(uint32_t timeSinceBoot) {
rgrover1 786:d6d7087d8377 315 TlmTimeSinceBoot = timeSinceBoot;
rgrover1 786:d6d7087d8377 316 }
rgrover1 771:26b809199308 317
rgrover1 786:d6d7087d8377 318 /*
rgrover1 786:d6d7087d8377 319 * callback function, called every 0.1s, incriments the TimeSinceBoot field in the TLM frame
rgrover1 786:d6d7087d8377 320 * @return nothing
rgrover1 786:d6d7087d8377 321 */
rgrover1 786:d6d7087d8377 322 void tsbCallback(void) {
rgrover1 786:d6d7087d8377 323 TlmTimeSinceBoot++;
rgrover1 771:26b809199308 324 }
rgrover1 771:26b809199308 325
rgrover1 771:26b809199308 326 /*
rgrover1 786:d6d7087d8377 327 * Update advertising data
rgrover1 786:d6d7087d8377 328 * @return true on success, false on failure
rgrover1 786:d6d7087d8377 329 */
rgrover1 786:d6d7087d8377 330 bool updateAdvPacket(uint8_t serviceData[], unsigned serviceDataLen) {
rgrover1 786:d6d7087d8377 331 // Fields from the Service
rgrover1 786:d6d7087d8377 332 DBG("Updating AdvFrame: %d", serviceDataLen);
rgrover1 832:5dac246f8f02 333
rgrover1 786:d6d7087d8377 334 ble.clearAdvertisingPayload();
rgrover1 830:a6ef72e0697a 335 ble.setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
rgrover1 830:a6ef72e0697a 336 ble.setAdvertisingInterval(100);
rgrover1 786:d6d7087d8377 337 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
rgrover1 786:d6d7087d8377 338 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_EDDYSTONE, sizeof(BEACON_EDDYSTONE));
rgrover1 786:d6d7087d8377 339 ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
rgrover1 786:d6d7087d8377 340
rgrover1 830:a6ef72e0697a 341
rgrover1 786:d6d7087d8377 342 return true;
rgrover1 786:d6d7087d8377 343 }
rgrover1 786:d6d7087d8377 344
rgrover1 786:d6d7087d8377 345 /*
rgrover1 786:d6d7087d8377 346 * State machine for switching out frames.
rgrover1 786:d6d7087d8377 347 * This function is called by the radioNotificationCallback when a frame needs to get swapped out.
rgrover1 786:d6d7087d8377 348 * This function exists because of time constraints in the radioNotificationCallback, so it is effectively
rgrover1 786:d6d7087d8377 349 * broken up into two functions.
rgrover1 786:d6d7087d8377 350 */
rgrover1 830:a6ef72e0697a 351 void swapOutFrames(FrameTypes frameType) {
rgrover1 832:5dac246f8f02 352 uint8_t serviceData[SERVICE_DATA_MAX];
rgrover1 771:26b809199308 353 unsigned serviceDataLen = 0;
rgrover1 786:d6d7087d8377 354 //hard code in the eddystone UUID
rgrover1 771:26b809199308 355 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[0];
rgrover1 771:26b809199308 356 serviceData[serviceDataLen++] = BEACON_EDDYSTONE[1];
rgrover1 771:26b809199308 357
rgrover1 771:26b809199308 358 // if certain frames are not enabled, then skip them. Worst case TLM is always enabled
rgrover1 832:5dac246f8f02 359 switch (frameType) {
rgrover1 830:a6ef72e0697a 360 case tlm:
rgrover1 830:a6ef72e0697a 361 // TLM frame
rgrover1 832:5dac246f8f02 362 if (tlmIsSet) {
rgrover1 832:5dac246f8f02 363 DBG("Swapping in TLM Frame: version=%x, Batt=%d, Temp = %d, PDUCnt = %d, TimeSinceBoot=%d",
rgrover1 832:5dac246f8f02 364 TlmVersion,
rgrover1 832:5dac246f8f02 365 TlmBatteryVoltage,
rgrover1 832:5dac246f8f02 366 TlmBeaconTemp,
rgrover1 832:5dac246f8f02 367 TlmPduCount,
rgrover1 832:5dac246f8f02 368 TlmTimeSinceBoot);
rgrover1 832:5dac246f8f02 369 serviceDataLen += constructTLMFrame(serviceData + serviceDataLen, 20);
rgrover1 832:5dac246f8f02 370 DBG("\t Swapping in TLM Frame: len=%d", serviceDataLen);
rgrover1 832:5dac246f8f02 371 updateAdvPacket(serviceData, serviceDataLen);
rgrover1 830:a6ef72e0697a 372 }
rgrover1 830:a6ef72e0697a 373 break;
rgrover1 830:a6ef72e0697a 374 case url:
rgrover1 771:26b809199308 375 // URL Frame
rgrover1 832:5dac246f8f02 376 if (urlIsSet) {
rgrover1 832:5dac246f8f02 377 DBG("Swapping in URL Frame: Power: %d", defaultUrlPower);
rgrover1 832:5dac246f8f02 378 serviceDataLen += constructURLFrame(serviceData + serviceDataLen, 20);
rgrover1 832:5dac246f8f02 379 DBG("\t Swapping in URL Frame: len=%d ", serviceDataLen);
rgrover1 832:5dac246f8f02 380 updateAdvPacket(serviceData, serviceDataLen);
rgrover1 830:a6ef72e0697a 381 //switchFlag = false;
rgrover1 771:26b809199308 382 }
rgrover1 830:a6ef72e0697a 383 break;
rgrover1 830:a6ef72e0697a 384 case uid:
rgrover1 771:26b809199308 385 // UID Frame
rgrover1 832:5dac246f8f02 386 if (uidIsSet) {
rgrover1 832:5dac246f8f02 387 DBG("Swapping in UID Frame: Power: %d", defaultUidPower);
rgrover1 832:5dac246f8f02 388 serviceDataLen += constructUIDFrame(serviceData + serviceDataLen, 20);
rgrover1 832:5dac246f8f02 389 DBG("\t Swapping in UID Frame: len=%d", serviceDataLen);
rgrover1 832:5dac246f8f02 390 updateAdvPacket(serviceData, serviceDataLen);
rgrover1 830:a6ef72e0697a 391 //switchFlag = false;
rgrover1 771:26b809199308 392 }
rgrover1 830:a6ef72e0697a 393 break;
rgrover1 771:26b809199308 394 default:
rgrover1 830:a6ef72e0697a 395 ERR("You have not initialized a Frame yet, please initialize one before starting a beacon");
rgrover1 830:a6ef72e0697a 396 ERR("uidIsSet = %d, urlIsSet = %d, tlmIsSet = %d", uidIsSet, urlIsSet, tlmIsSet);
rgrover1 830:a6ef72e0697a 397 }
rgrover1 830:a6ef72e0697a 398 }
rgrover1 830:a6ef72e0697a 399
rgrover1 830:a6ef72e0697a 400 /*
rgrover1 830:a6ef72e0697a 401 * Callback to swap in URL frame
rgrover1 830:a6ef72e0697a 402 */
rgrover1 830:a6ef72e0697a 403 void urlCallback(void) {
rgrover1 830:a6ef72e0697a 404 DBG("urlCallback");
rgrover1 832:5dac246f8f02 405 if (false == advLock) {
rgrover1 830:a6ef72e0697a 406 advLock = true;
rgrover1 830:a6ef72e0697a 407 DBG("advLock = url")
rgrover1 830:a6ef72e0697a 408 frameIndex = url;
rgrover1 830:a6ef72e0697a 409 swapOutFrames(frameIndex);
rgrover1 830:a6ef72e0697a 410 ble.startAdvertising();
rgrover1 830:a6ef72e0697a 411 } else {
rgrover1 830:a6ef72e0697a 412 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
rgrover1 832:5dac246f8f02 413 INFO("URI(%d) cannot complete, %d is currently broadcasting", url, frameIndex);
rgrover1 830:a6ef72e0697a 414 FrameTypes x = url;
rgrover1 830:a6ef72e0697a 415 overflow.push(x);
rgrover1 830:a6ef72e0697a 416 }
rgrover1 830:a6ef72e0697a 417 }
rgrover1 830:a6ef72e0697a 418
rgrover1 830:a6ef72e0697a 419 /*
rgrover1 830:a6ef72e0697a 420 * Callback to swap in UID frame
rgrover1 830:a6ef72e0697a 421 */
rgrover1 830:a6ef72e0697a 422 void uidCallback(void) {
rgrover1 830:a6ef72e0697a 423 DBG("uidCallback");
rgrover1 832:5dac246f8f02 424 if (false == advLock) {
rgrover1 830:a6ef72e0697a 425 advLock = true;
rgrover1 830:a6ef72e0697a 426 DBG("advLock = uid")
rgrover1 830:a6ef72e0697a 427 frameIndex = uid;
rgrover1 830:a6ef72e0697a 428 swapOutFrames(frameIndex);
rgrover1 830:a6ef72e0697a 429 ble.startAdvertising();
rgrover1 830:a6ef72e0697a 430 } else {
rgrover1 830:a6ef72e0697a 431 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
rgrover1 832:5dac246f8f02 432 INFO("UID(%d) cannot complete, %d is currently broadcasting", uid, frameIndex);
rgrover1 830:a6ef72e0697a 433 FrameTypes x = uid; // have to do this to satisfy cont vs volatile keywords... sigh...
rgrover1 830:a6ef72e0697a 434 overflow.push(x);
rgrover1 830:a6ef72e0697a 435 }
rgrover1 830:a6ef72e0697a 436 }
rgrover1 830:a6ef72e0697a 437
rgrover1 830:a6ef72e0697a 438 /*
rgrover1 830:a6ef72e0697a 439 * Callback to swap in TLM frame
rgrover1 830:a6ef72e0697a 440 */
rgrover1 830:a6ef72e0697a 441 void tlmCallback(void) {
rgrover1 830:a6ef72e0697a 442 DBG("tlmCallback");
rgrover1 832:5dac246f8f02 443 if (false == advLock) {
rgrover1 830:a6ef72e0697a 444 // OK to broadcast
rgrover1 830:a6ef72e0697a 445 advLock = true;
rgrover1 830:a6ef72e0697a 446 DBG("advLock = tlm")
rgrover1 830:a6ef72e0697a 447 frameIndex = tlm;
rgrover1 830:a6ef72e0697a 448 swapOutFrames(frameIndex);
rgrover1 830:a6ef72e0697a 449 ble.startAdvertising();
rgrover1 830:a6ef72e0697a 450 } else {
rgrover1 830:a6ef72e0697a 451 // Someone else is broadcasting, toss it into the overflow buffer to retransmit when free
rgrover1 832:5dac246f8f02 452 INFO("TLM(%d) cannot complete, %d is currently broadcasting", tlm, frameIndex);
rgrover1 830:a6ef72e0697a 453 FrameTypes x = tlm;
rgrover1 830:a6ef72e0697a 454 overflow.push(x);
rgrover1 830:a6ef72e0697a 455 }
rgrover1 830:a6ef72e0697a 456 }
rgrover1 830:a6ef72e0697a 457
rgrover1 830:a6ef72e0697a 458 void stopAdvCallback(void) {
rgrover1 832:5dac246f8f02 459 if (overflow.empty()) {
rgrover1 830:a6ef72e0697a 460 // if nothing left to transmit, stop
rgrover1 830:a6ef72e0697a 461 ble.stopAdvertising();
rgrover1 830:a6ef72e0697a 462 advLock = false; // unlock lock
rgrover1 830:a6ef72e0697a 463 } else {
rgrover1 830:a6ef72e0697a 464 // transmit other packets at current time index
rgrover1 830:a6ef72e0697a 465 FrameTypes x = NONE;
rgrover1 830:a6ef72e0697a 466 overflow.pop(x);
rgrover1 832:5dac246f8f02 467 INFO("Re-Transmitting %d", x);
rgrover1 830:a6ef72e0697a 468 swapOutFrames(x);
rgrover1 771:26b809199308 469 }
rgrover1 771:26b809199308 470 }
rgrover1 771:26b809199308 471
rgrover1 771:26b809199308 472 /*
rgrover1 786:d6d7087d8377 473 * Callback from onRadioNotification(), used to update the PDUCounter and process next state.
rgrover1 786:d6d7087d8377 474 */
rgrover1 786:d6d7087d8377 475 #define EDDYSTONE_SWAPFRAME_DELAYMS 1
rgrover1 771:26b809199308 476 void radioNotificationCallback(bool radioActive) {
rgrover1 771:26b809199308 477 // Update PDUCount
rgrover1 771:26b809199308 478 TlmPduCount++;
rgrover1 830:a6ef72e0697a 479 // True just before an frame is sent, false just after a frame is sent
rgrover1 832:5dac246f8f02 480 if (radioActive) {
rgrover1 786:d6d7087d8377 481 // Do Nothing
rgrover1 786:d6d7087d8377 482 } else {
rgrover1 830:a6ef72e0697a 483 // Packet has been sent, disable advertising
rgrover1 830:a6ef72e0697a 484 stopAdv.attach_us(this, &EddystoneService::stopAdvCallback, 1);
rgrover1 771:26b809199308 485 }
rgrover1 786:d6d7087d8377 486 }
rgrover1 786:d6d7087d8377 487
rgrover1 786:d6d7087d8377 488 /*
rgrover1 786:d6d7087d8377 489 * This function explicityly sets the parameters used by the Eddystone beacon.
rgrover1 786:d6d7087d8377 490 * this function should be used in leu of the config service.
rgrover1 786:d6d7087d8377 491 *
rgrover1 786:d6d7087d8377 492 * @param bleIn ble object used to broadcast eddystone information
rgrover1 830:a6ef72e0697a 493 * @param beaconPeriodus is how often ble broadcasts are mde, in mili seconds
rgrover1 786:d6d7087d8377 494 * @param txPowerLevel sets the broadcasting power level.
rgrover1 786:d6d7087d8377 495 *
rgrover1 786:d6d7087d8377 496 */
rgrover1 832:5dac246f8f02 497 EddystoneService(BLEDevice &bleIn,
rgrover1 832:5dac246f8f02 498 uint16_t beaconPeriodus = 100,
rgrover1 832:5dac246f8f02 499 uint8_t txPowerIn = 0) :
rgrover1 830:a6ef72e0697a 500 ble(bleIn),
rgrover1 830:a6ef72e0697a 501 advPeriodus(beaconPeriodus),
rgrover1 830:a6ef72e0697a 502 txPower(txPowerIn),
rgrover1 830:a6ef72e0697a 503 advLock(false),
rgrover1 830:a6ef72e0697a 504 frameIndex(NONE) {
rgrover1 830:a6ef72e0697a 505 }
rgrover1 830:a6ef72e0697a 506
rgrover1 830:a6ef72e0697a 507 /*
rgrover1 830:a6ef72e0697a 508 * @breif this function starts eddystone advertising based on configured frames.
rgrover1 830:a6ef72e0697a 509 */
rgrover1 830:a6ef72e0697a 510 void start(void) {
rgrover1 830:a6ef72e0697a 511 // Initialize Frame transition, start with URL to pass eddystone validator app on first try
rgrover1 830:a6ef72e0697a 512 if (urlIsSet) {
rgrover1 830:a6ef72e0697a 513 frameIndex = url;
rgrover1 830:a6ef72e0697a 514 urlTicker.attach(this, &EddystoneService::urlCallback, urlAdvPeriod);
rgrover1 830:a6ef72e0697a 515 DBG("attached urlCallback every %d seconds", urlAdvPeriod);
rgrover1 786:d6d7087d8377 516 }
rgrover1 830:a6ef72e0697a 517 if (uidIsSet) {
rgrover1 830:a6ef72e0697a 518 frameIndex = uid;
rgrover1 830:a6ef72e0697a 519 uidTicker.attach(this, &EddystoneService::uidCallback, uidAdvPeriod);
rgrover1 830:a6ef72e0697a 520 DBG("attached uidCallback every %d seconds", uidAdvPeriod);
rgrover1 830:a6ef72e0697a 521 }
rgrover1 832:5dac246f8f02 522 if (tlmIsSet) {
rgrover1 830:a6ef72e0697a 523 frameIndex = tlm;
rgrover1 830:a6ef72e0697a 524 // Make double sure the PDUCount and TimeSinceBoot fields are set to zero at reset
rgrover1 830:a6ef72e0697a 525 updateTlmPduCount(0);
rgrover1 830:a6ef72e0697a 526 updateTlmTimeSinceBoot(0);
rgrover1 832:5dac246f8f02 527 timeSinceBootTick.attach(this, &EddystoneService::tsbCallback, 0.1); // incriment the TimeSinceBoot ticker every 0.1s
rgrover1 830:a6ef72e0697a 528 tlmTicker.attach(this, &EddystoneService::tlmCallback, TlmAdvPeriod);
rgrover1 830:a6ef72e0697a 529 DBG("attached tlmCallback every %d seconds", TlmAdvPeriod);
rgrover1 830:a6ef72e0697a 530 }
rgrover1 832:5dac246f8f02 531 if (NONE == frameIndex) {
rgrover1 830:a6ef72e0697a 532 error("No Frames were Initialized! Please initialize a frame before starting an eddystone beacon.");
rgrover1 830:a6ef72e0697a 533 }
rgrover1 830:a6ef72e0697a 534 //uidRFU = 0;
rgrover1 786:d6d7087d8377 535
rgrover1 832:5dac246f8f02 536 ble.setTxPower(txPower);
rgrover1 832:5dac246f8f02 537 ble.gap().onRadioNotification(this, &EddystoneService::radioNotificationCallback);
rgrover1 771:26b809199308 538 }
rgrover1 771:26b809199308 539
rgrover1 771:26b809199308 540 private:
rgrover1 786:d6d7087d8377 541
rgrover1 830:a6ef72e0697a 542 // Eddystone Variables
rgrover1 786:d6d7087d8377 543 BLEDevice &ble;
rgrover1 830:a6ef72e0697a 544 uint16_t advPeriodus;
rgrover1 830:a6ef72e0697a 545 uint8_t txPower;
rgrover1 830:a6ef72e0697a 546 Ticker timeSinceBootTick; // counter that counts time since boot
rgrover1 830:a6ef72e0697a 547 volatile bool advLock;
rgrover1 830:a6ef72e0697a 548 volatile FrameTypes frameIndex;
rgrover1 830:a6ef72e0697a 549 Timeout stopAdv;
rgrover1 830:a6ef72e0697a 550
rgrover1 830:a6ef72e0697a 551
rgrover1 830:a6ef72e0697a 552 // URI Frame Variables
rgrover1 830:a6ef72e0697a 553 uint8_t defaultUriDataLength;
rgrover1 786:d6d7087d8377 554 UriData_t defaultUriData;
rgrover1 830:a6ef72e0697a 555 int8_t defaultUrlPower;
rgrover1 830:a6ef72e0697a 556 bool urlIsSet; // flag that enables / disable URI Frames
rgrover1 830:a6ef72e0697a 557 uint32_t urlAdvPeriod; // how long the url frame will be advertised for
rgrover1 830:a6ef72e0697a 558 Ticker urlTicker;
rgrover1 830:a6ef72e0697a 559
rgrover1 830:a6ef72e0697a 560 // UID Frame Variables
rgrover1 786:d6d7087d8377 561 UIDNamespaceID_t defaultUidNamespaceID;
rgrover1 786:d6d7087d8377 562 UIDInstanceID_t defaultUidInstanceID;
rgrover1 786:d6d7087d8377 563 int8_t defaultUidPower;
rgrover1 786:d6d7087d8377 564 uint16_t uidRFU;
rgrover1 830:a6ef72e0697a 565 bool uidIsSet; // flag that enables / disable UID Frames
rgrover1 830:a6ef72e0697a 566 uint32_t uidAdvPeriod; // how long the uid frame will be advertised for
rgrover1 830:a6ef72e0697a 567 Ticker uidTicker;
rgrover1 786:d6d7087d8377 568
rgrover1 830:a6ef72e0697a 569 // TLM Frame Variables
rgrover1 832:5dac246f8f02 570 uint8_t TlmVersion;
rgrover1 832:5dac246f8f02 571 volatile uint16_t TlmBatteryVoltage;
rgrover1 832:5dac246f8f02 572 volatile uint16_t TlmBeaconTemp;
rgrover1 832:5dac246f8f02 573 volatile uint32_t TlmPduCount;
rgrover1 832:5dac246f8f02 574 volatile uint32_t TlmTimeSinceBoot;
rgrover1 832:5dac246f8f02 575 bool tlmIsSet; // flag that enables / disables TLM frames
rgrover1 832:5dac246f8f02 576 uint32_t TlmAdvPeriod; // number of minutes between adv frames
rgrover1 832:5dac246f8f02 577 Ticker tlmTicker;
rgrover1 771:26b809199308 578
rgrover1 771:26b809199308 579 public:
rgrover1 771:26b809199308 580 /*
rgrover1 771:26b809199308 581 * Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
rgrover1 771:26b809199308 582 */
rgrover1 830:a6ef72e0697a 583 static void encodeURL(const char *uriDataIn, UriData_t uriDataOut, uint8_t &sizeofURIDataOut) {
rgrover1 832:5dac246f8f02 584 DBG("Encode URL = %s", uriDataIn);
rgrover1 832:5dac246f8f02 585 const char *prefixes[] = {
rgrover1 771:26b809199308 586 "http://www.",
rgrover1 771:26b809199308 587 "https://www.",
rgrover1 771:26b809199308 588 "http://",
rgrover1 771:26b809199308 589 "https://",
rgrover1 771:26b809199308 590 };
rgrover1 771:26b809199308 591 const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
rgrover1 832:5dac246f8f02 592 const char *suffixes[] = {
rgrover1 771:26b809199308 593 ".com/",
rgrover1 771:26b809199308 594 ".org/",
rgrover1 771:26b809199308 595 ".edu/",
rgrover1 771:26b809199308 596 ".net/",
rgrover1 771:26b809199308 597 ".info/",
rgrover1 771:26b809199308 598 ".biz/",
rgrover1 771:26b809199308 599 ".gov/",
rgrover1 771:26b809199308 600 ".com",
rgrover1 771:26b809199308 601 ".org",
rgrover1 771:26b809199308 602 ".edu",
rgrover1 771:26b809199308 603 ".net",
rgrover1 771:26b809199308 604 ".info",
rgrover1 771:26b809199308 605 ".biz",
rgrover1 771:26b809199308 606 ".gov"
rgrover1 771:26b809199308 607 };
rgrover1 771:26b809199308 608 const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
rgrover1 771:26b809199308 609
rgrover1 771:26b809199308 610 sizeofURIDataOut = 0;
rgrover1 771:26b809199308 611 memset(uriDataOut, 0, sizeof(UriData_t));
rgrover1 771:26b809199308 612
rgrover1 771:26b809199308 613 if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
rgrover1 771:26b809199308 614 return;
rgrover1 771:26b809199308 615 }
rgrover1 771:26b809199308 616
rgrover1 771:26b809199308 617 /*
rgrover1 771:26b809199308 618 * handle prefix
rgrover1 771:26b809199308 619 */
rgrover1 771:26b809199308 620 for (unsigned i = 0; i < NUM_PREFIXES; i++) {
rgrover1 771:26b809199308 621 size_t prefixLen = strlen(prefixes[i]);
rgrover1 771:26b809199308 622 if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
rgrover1 771:26b809199308 623 uriDataOut[sizeofURIDataOut++] = i;
rgrover1 771:26b809199308 624 uriDataIn += prefixLen;
rgrover1 771:26b809199308 625 break;
rgrover1 771:26b809199308 626 }
rgrover1 771:26b809199308 627 }
rgrover1 771:26b809199308 628
rgrover1 771:26b809199308 629 /*
rgrover1 771:26b809199308 630 * handle suffixes
rgrover1 771:26b809199308 631 */
rgrover1 771:26b809199308 632 while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
rgrover1 771:26b809199308 633 /* check for suffix match */
rgrover1 771:26b809199308 634 unsigned i;
rgrover1 771:26b809199308 635 for (i = 0; i < NUM_SUFFIXES; i++) {
rgrover1 771:26b809199308 636 size_t suffixLen = strlen(suffixes[i]);
rgrover1 771:26b809199308 637 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
rgrover1 771:26b809199308 638 uriDataOut[sizeofURIDataOut++] = i;
rgrover1 771:26b809199308 639 uriDataIn += suffixLen;
rgrover1 771:26b809199308 640 break; /* from the for loop for checking against suffixes */
rgrover1 771:26b809199308 641 }
rgrover1 771:26b809199308 642 }
rgrover1 771:26b809199308 643 /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
rgrover1 830:a6ef72e0697a 644 INFO("Encoding URI: No Suffix Found");
rgrover1 771:26b809199308 645 if (i == NUM_SUFFIXES) {
rgrover1 771:26b809199308 646 uriDataOut[sizeofURIDataOut++] = *uriDataIn;
rgrover1 771:26b809199308 647 ++uriDataIn;
rgrover1 771:26b809199308 648 }
rgrover1 771:26b809199308 649 }
rgrover1 771:26b809199308 650 }
rgrover1 771:26b809199308 651 };
rgrover1 771:26b809199308 652
rgrover1 771:26b809199308 653 #endif // SERVICES_EDDYSTONEBEACON_H_