High level Bluetooth Low Energy API and radio abstraction layer

Dependencies:   nRF51822

Dependents:   LinkNode_LIS3DH

Fork of BLE_API by Bluetooth Low Energy

Committer:
rgrover1
Date:
Mon Nov 02 09:09:05 2015 +0000
Revision:
851:802f445cc195
Parent:
850:32ff6e392630
Child:
857:7f578be2d01d
Synchronized with git rev 129683bd
Author: Vincent Coubard
Code and command cleanup:
- add a space after if keyword
- Use typedef types instead of direct declarations for
pFunctionPointerWithContext_t and pvoidfcontext_t
- Fix typos and enhance comment about how alignement and size
requirements of the member function pointer are computed.

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 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_