Skip to content

Commit 5e4ad5c

Browse files
author
Mikael Kindborg
committed
Added generated examples after update of easyble.js and eddystone.js
1 parent 311d5fa commit 5e4ad5c

File tree

16 files changed

+4450
-2419
lines changed
  • generated/examples
    • arduino-led-onoff-ble/app/libs/evothings/easyble
    • bluno-helloworld/app/libs/evothings/easyble
    • eddystone-scan/libs/evothings
    • lightblue-bean-basic/app/libs/evothings/easyble
    • mbed-custom-gap/libs/evothings/easyble
    • mbed-custom-gatt/libs/evothings/easyble
    • nordic-nRF51-dk-ble/app/libs/evothings/easyble
    • nordic-nRF51822-ek-ble/libs/evothings/easyble
    • redbearlab-simplechat/libs/evothings/easyble
    • redbearlab-simplecontrol/libs/evothings/easyble
    • rfduino-led-onoff/app/libs/evothings/easyble
    • ti-sensortag-accelerometer/libs/evothings/easyble
    • ti-sensortag-cc2541-demo/libs/evothings/easyble
    • ti-sensortag-cc2650-demo/libs/evothings/easyble
    • ti-sensortag-sensors/libs/evothings/easyble

16 files changed

+4450
-2419
lines changed

generated/examples/arduino-led-onoff-ble/app/libs/evothings/easyble/easyble.js

+283-157
Large diffs are not rendered by default.

generated/examples/bluno-helloworld/app/libs/evothings/easyble/easyble.js

+283-157
Large diffs are not rendered by default.

generated/examples/eddystone-scan/libs/evothings/easyble/easyble.js

+283-157
Large diffs are not rendered by default.

generated/examples/eddystone-scan/libs/evothings/eddystone/eddystone.js

+205-64
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,62 @@
55
// The protocol specification is available at:
66
// https://github.com/google/eddystone
77

8+
;(function() {
9+
810
// prerequisites
911
evothings.loadScripts([
1012
'libs/evothings/easyble/easyble.js',
1113
])
1214

15+
/**
16+
* @namespace
17+
* @description <p>Library for Eddystone beacons.</p>
18+
* <p>It is safe practise to call function {@link evothings.scriptsLoaded}
19+
* to ensure dependent libraries are loaded before calling functions
20+
* in this library.</p>
21+
*/
1322
evothings.eddystone = {};
1423

15-
;(function() {
1624
// constants
1725
var BLUETOOTH_BASE_UUID = '-0000-1000-8000-00805f9b34fb';
1826

1927
// false when scanning is off. true when on.
2028
var isScanning = false;
2129

22-
/** Starts scanning for Eddystone devices.
23-
* <p>Found devices and errors will be reported to the supplied callbacks.</p>
24-
* <p>Will keep scanning indefinitely until you call stopScan().</p>
25-
* To conserve energy, call stopScan() as soon as you've found the device you're looking for.
26-
* <p>Calling this function while scanning is in progress will fail.</p>
27-
*
28-
* @param {scanCallback} win
29-
* @param {failCallback} fail
30-
*/
31-
evothings.eddystone.startScan = function(win, fail) {
30+
/**
31+
* @description Starts scanning for Eddystone devices.
32+
* <p>Found devices and errors will be reported to the supplied callbacks.</p>
33+
* <p>Will keep scanning indefinitely until you call stopScan().</p>
34+
* <p>To conserve energy, call stopScan() as soon as you've found the device
35+
* you're looking for.</p>
36+
* <p>Calling startScan() while scanning is in progress will produce an error.</p>
37+
*
38+
* @param {evothings.eddystone.scanCallback} - Success function called
39+
* when a beacon is found.
40+
* @param {evothings.eddystone.failCallback} - Error callback: fail(error).
41+
*
42+
* @public
43+
*
44+
* @example
45+
* evothings.eddystone.startScan(
46+
* function(beacon)
47+
* {
48+
* console.log('Found beacon: ' + beacon.url);
49+
* },
50+
* function(error)
51+
* {
52+
* console.log('Scan error: ' + error);
53+
* });
54+
*/
55+
evothings.eddystone.startScan = function(scanCallback, failCallback)
56+
{
57+
// Internal callback variable names.
58+
var win = scanCallback;
59+
var fail = failCallback;
60+
3261
// If scanning is already in progress, fail.
33-
if(isScanning) {
62+
if(isScanning)
63+
{
3464
fail("Scanning already in progress!");
3565
return;
3666
}
@@ -40,94 +70,185 @@ evothings.eddystone.startScan = function(win, fail) {
4070
// The device object given in this callback is reused by easyble.
4171
// Therefore we can store data in it and expect to have the data still be there
4272
// on the next callback with the same device.
43-
evothings.easyble.startScan(function(device) {
44-
// A device might be an Eddystone if it has advertisementData...
45-
var ad = device.advertisementData;
46-
if(!ad) return;
47-
// With serviceData...
48-
var sd = ad.kCBAdvDataServiceData;
49-
if(!sd) return;
50-
// And the 0xFEAA service.
51-
var base64data = sd['0000feaa'+BLUETOOTH_BASE_UUID];
52-
if(!base64data) return;
53-
var byteArray = evothings.util.base64DecToArr(base64data);
54-
55-
// If the data matches one of the Eddystone frame formats,
56-
// we can forward it to the user.
57-
if(parseFrameUID(device, byteArray, win, fail)) return;
58-
if(parseFrameURL(device, byteArray, win, fail)) return;
59-
if(parseFrameTLM(device, byteArray, win, fail)) return;
60-
61-
}, function(error) {
62-
fail(error);
63-
});
73+
evothings.easyble.startScan(
74+
function(device)
75+
{
76+
// A device might be an Eddystone if it has advertisementData...
77+
var ad = device.advertisementData;
78+
if(!ad) return;
79+
// With serviceData...
80+
var sd = ad.kCBAdvDataServiceData;
81+
if(!sd) return;
82+
// And the 0xFEAA service.
83+
var base64data = sd['0000feaa'+BLUETOOTH_BASE_UUID];
84+
if(!base64data) return;
85+
var byteArray = evothings.util.base64DecToArr(base64data);
86+
87+
// If the data matches one of the Eddystone frame formats,
88+
// we can forward it to the user.
89+
if(parseFrameUID(device, byteArray, win, fail)) return;
90+
if(parseFrameURL(device, byteArray, win, fail)) return;
91+
if(parseFrameTLM(device, byteArray, win, fail)) return;
92+
},
93+
function(error)
94+
{
95+
fail(error);
96+
});
6497
}
6598

66-
/** This function is a parameter to startScan() and is called when a new device is discovered.
67-
* @callback scanCallback
68-
* @param {EddystoneDevice} device
69-
*/
99+
/**
100+
* @description This function is a parameter to startScan() and
101+
* is called when a beacons is discovered/updated.
102+
* @callback evothings.eddystone.scanCallback
103+
* @param {evothings.eddystone.EddystoneDevice} beacon - Beacon
104+
* found during scanning.
105+
*/
70106

71-
/** Object representing a BLE device. Inherits from evothings.easyble.EasyBLEDevice.
72-
* All uninherited properties are optional; they may be missing.
73-
* @typedef {Object} EddystoneDevice
74-
* @property {string} url - An Internet URL.
75-
* @property {number} txPower - A signed integer, the signal strength in decibels, factory-measured at a range of 0 meters.
76-
* @property {Uint8Array} nid - 10-byte namespace ID.
77-
* @property {Uint8Array} bid - 6-byte beacon ID.
78-
* @property {number} voltage - Device's battery voltage, in millivolts, or 0 (zero) if device is not battery-powered.
79-
* @property {number} temperature - Device's ambient temperature in 256:ths of degrees Celcius, or 0x8000 if device has no thermometer.
80-
* @property {number} adv_cnt - Count of advertisement frames sent since device's startup.
81-
* @property {number} dsec_cnt - Time since device's startup, in deci-seconds (10 units equals 1 second).
82-
*/
107+
/**
108+
* @description This function is called when an operation fails.
109+
* @callback evothings.eddystone.failCallback
110+
* @param {string} errorString - A human-readable string that
111+
* describes the error that occurred.
112+
*/
83113

84-
/** Stop scanning for Eddystone devices.
114+
/**
115+
* @description Object representing a BLE device. Inherits from
116+
* {@link evothings.easyble.EasyBLEDevice}.
117+
* Which properties are available depends on which packets types broadcasted
118+
* by the beacon. Properties may be undefined. Typically properties are populated
119+
* as scanning processes.
120+
* @typedef {Object} evothings.eddystone.EddystoneDevice
121+
* @property {string} url - An Internet URL.
122+
* @property {number} txPower - A signed integer, the signal strength in decibels,
123+
* factory-measured at a range of 0 meters.
124+
* @property {Uint8Array} nid - 10-byte namespace ID.
125+
* @property {Uint8Array} bid - 6-byte beacon ID.
126+
* @property {number} voltage - Device's battery voltage, in millivolts,
127+
* or 0 (zero) if device is not battery-powered.
128+
* @property {number} temperature - Device's ambient temperature in 256:ths of
129+
* degrees Celcius, or 0x8000 if device has no thermometer.
130+
* @property {number} adv_cnt - Count of advertisement frames sent since device's startup.
131+
* @property {number} dsec_cnt - Time since device's startup, in deci-seconds
132+
* (10 units equals 1 second).
85133
*/
86-
evothings.eddystone.stopScan = function() {
134+
135+
/**
136+
* @description Stop scanning for Eddystone devices.
137+
* @public
138+
* @example
139+
* evothings.eddystone.stopScan();
140+
*/
141+
evothings.eddystone.stopScan = function()
142+
{
87143
evothings.easyble.stopScan();
88144
isScanning = false;
89145
}
90146

147+
/**
148+
* @description Calculate the accuracy (distance in meters) of the beacon.
149+
* <p>The beacon distance calculation uses txPower at 1 meters, but the
150+
* Eddystone protocol reports the value at 0 meters. 41dBm is the signal
151+
* loss that occurs over 1 meter, this value is subtracted by default
152+
* from the reported txPower. You can tune the calculation by adding
153+
* or subtracting to param txPower.<p>
154+
* <p>Note that the returned distance value is not accurate, and that
155+
* it fluctuates over time. Sampling/filtering over time is recommended
156+
* to obtain a stable value.<p>
157+
* @public
158+
* @param txPower The txPower of the beacon.
159+
* @param rssi The RSSI of the beacon, subtract or add to this value to
160+
* tune the dBm strength. 41dBm is subtracted from this value in the
161+
* distance algorithm used by calculateAccuracy.
162+
* @return Distance in meters, or null if unable to compute distance
163+
* (occurs for example when txPower or rssi is undefined).
164+
* @example
165+
* // Note that beacon.txPower and beacon.rssi many be undefined,
166+
* // in which case calculateAccuracy returns null. This happens
167+
* // before txPower and rssi have been reported by the beacon.
168+
* var distance = evothings.eddystone.calculateAccuracy(
169+
* beacon.txPower, beacon.rssi);
170+
*/
171+
evothings.eddystone.calculateAccuracy = function(txPower, rssi)
172+
{
173+
if (!rssi || rssi >= 0 || !txPower)
174+
{
175+
return null
176+
}
177+
178+
// Algorithm
179+
// http://developer.radiusnetworks.com/2014/12/04/fundamentals-of-beacon-ranging.html
180+
// http://stackoverflow.com/questions/21338031/radius-networks-ibeacon-ranging-fluctuation
181+
182+
// The beacon distance formula uses txPower at 1 meters, but the Eddystone
183+
// protocol reports the value at 0 meters. 41dBm is the signal loss that
184+
// occurs over 1 meter, so we subtract that from the reported txPower.
185+
var ratio = rssi * 1.0 / (txPower - 41)
186+
if (ratio < 1.0)
187+
{
188+
return Math.pow(ratio, 10)
189+
}
190+
else
191+
{
192+
var accuracy = (0.89976) * Math.pow(ratio, 7.7095) + 0.111
193+
return accuracy
194+
}
195+
}
196+
91197
// Return true on frame type recognition, false otherwise.
92-
function parseFrameUID(device, data, win, fail) {
198+
function parseFrameUID(device, data, win, fail)
199+
{
93200
if(data[0] != 0x00) return false;
201+
94202
// The UID frame has 18 bytes + 2 bytes reserved for future use
95203
// https://github.com/google/eddystone/tree/master/eddystone-uid
96204
// Check that we got at least 18 bytes.
97-
if(data.byteLength < 18) {
205+
if(data.byteLength < 18)
206+
{
98207
fail("UID frame: invalid byteLength: "+data.byteLength);
99208
return true;
100209
}
210+
101211
device.txPower = evothings.util.littleEndianToInt8(data, 1);
102212
device.nid = data.subarray(2, 12); // Namespace ID.
103213
device.bid = data.subarray(12, 18); // Beacon ID.
214+
104215
win(device);
216+
105217
return true;
106218
}
107219

108-
function parseFrameURL(device, data, win, fail) {
220+
function parseFrameURL(device, data, win, fail)
221+
{
109222
if(data[0] != 0x10) return false;
110-
if(data.byteLength < 4) {
223+
224+
if(data.byteLength < 4)
225+
{
111226
fail("URL frame: invalid byteLength: "+data.byteLength);
112227
return true;
113228
}
229+
114230
device.txPower = evothings.util.littleEndianToInt8(data, 1);
115-
var url;
231+
116232
// URL scheme prefix
233+
var url;
117234
switch(data[2]) {
118235
case 0: url = 'http://www.'; break;
119236
case 1: url = 'https://www.'; break;
120237
case 2: url = 'http://'; break;
121238
case 3: url = 'https://'; break;
122239
default: fail("URL frame: invalid prefix: "+data[2]); return true;
123240
}
241+
124242
// Process each byte in sequence.
125243
var i = 3;
126-
while(i < data.byteLength) {
244+
while(i < data.byteLength)
245+
{
127246
var c = data[i];
128247
// A byte is either a top-domain shortcut, or a printable ascii character.
129-
if(c < 14) {
130-
switch(c) {
248+
if(c < 14)
249+
{
250+
switch(c)
251+
{
131252
case 0: url += '.com/'; break;
132253
case 1: url += '.org/'; break;
133254
case 2: url += '.edu/'; break;
@@ -143,44 +264,64 @@ function parseFrameURL(device, data, win, fail) {
143264
case 12: url += '.biz'; break;
144265
case 13: url += '.gov'; break;
145266
}
146-
} else if(c < 32 || c >= 127) {
267+
}
268+
else if(c < 32 || c >= 127)
269+
{
147270
// Unprintables are not allowed.
148271
fail("URL frame: invalid character: "+data[2]);
149272
return true;
150-
} else {
273+
}
274+
else
275+
{
151276
url += String.fromCharCode(c);
152277
}
153278

154279
i += 1;
155280
}
281+
282+
// Set URL field of the device.
156283
device.url = url;
284+
157285
win(device);
286+
158287
return true;
159288
}
160289

161-
function parseFrameTLM(device, data, win, fail) {
290+
function parseFrameTLM(device, data, win, fail)
291+
{
162292
if(data[0] != 0x20) return false;
163-
if(data[1] != 0x00) {
293+
294+
if(data[1] != 0x00)
295+
{
164296
fail("TLM frame: unknown version: "+data[1]);
297+
165298
return true;
166299
}
167-
if(data.byteLength != 14) {
300+
301+
if(data.byteLength != 14)
302+
{
168303
fail("TLM frame: invalid byteLength: "+data.byteLength);
304+
169305
return true;
170306
}
171307

172308
device.voltage = evothings.util.bigEndianToUint16(data, 2);
173309

174310
var temp = evothings.util.bigEndianToUint16(data, 4);
175311
if(temp == 0x8000)
312+
{
176313
device.temperature = 0x8000;
314+
}
177315
else
316+
{
178317
device.temperature = evothings.util.bigEndianToInt16(data, 4) / 256.0;
318+
}
179319

180320
device.adv_cnt = evothings.util.bigEndianToUint32(data, 6);
181321
device.dsec_cnt = evothings.util.bigEndianToUint32(data, 10);
182322

183323
win(device);
324+
184325
return true;
185326
}
186327

0 commit comments

Comments
 (0)