Pinned to some recent date

Committer:
Simon Cooksey
Date:
Thu Nov 17 16:43:53 2016 +0000
Revision:
0:fb7af294d5d9
Initial commit

Who changed what in which revision?

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