Comparing version 0.0.3 to 0.0.4
@@ -7,4 +7,6 @@ /** | ||
var pdu = require('../../common/util/pdu.js'); | ||
var companyIdentifierCodes = require('../../common/assignednumbers/companyidentifiercodes.js'); | ||
/** | ||
/** | ||
* Parse BLE advertiser data manufacturer specific data. | ||
@@ -17,26 +19,120 @@ * @param {string} payload The raw payload as a hexadecimal-string. | ||
var companyIdentifierCode = payload.substr(cursor+6, 2); | ||
companyIdentifierCode += payload.substr(cursor+4, 2); | ||
var companyName = companyIdentifierCodes.companyNames[companyIdentifierCode]; | ||
var data = payload.substr(cursor+8, pdu.getTagDataLength(payload, cursor)-4); | ||
advertiserData.manufacturerSpecificData = { | ||
companyName : companyName, | ||
companyIdentifierCode: companyIdentifierCode, | ||
data: data }; | ||
var isApple = (companyIdentifierCode == "004c"); | ||
// Apple proprietary data | ||
if(companyIdentifierCode === '004c') { | ||
var appleType = data.substr(0,2); | ||
switch(appleType) { | ||
case '02': | ||
processIBeacon(data, advertiserData); | ||
break; | ||
case '09': | ||
// TODO: determine what this is and process it | ||
break; | ||
default: | ||
} | ||
} | ||
var isIBeacon = (data.substr(0,4) == "0215"); | ||
// StickNFind proprietary data | ||
if(companyIdentifierCode === '00f9') { | ||
var packetType = data.substr(0,2); | ||
switch(packetType) { | ||
case '01': | ||
processSnFSingle(data, advertiserData); | ||
break; | ||
case '42': | ||
processSnSMotion(data, advertiserData); | ||
break; | ||
default: | ||
} | ||
} | ||
} | ||
if(isApple && isIBeacon) { | ||
var iBeacon = {}; | ||
iBeacon.uuid = data.substr(4,32); | ||
iBeacon.major = data.substr(36,4); | ||
iBeacon.minor = data.substr(40,4); | ||
iBeacon.txPower = pdu.convertTxPower(data.substr(44,2)); | ||
advertiserData.manufacturerSpecificData.iBeacon = iBeacon; | ||
/** | ||
* Parse Apple iBeacon manufacturer specific data. | ||
* @param {string} data The manufacturer-specific data as hex string. | ||
* @param {Object} advertiserData The object containing all parsed data. | ||
*/ | ||
function processIBeacon(data, advertiserData) { | ||
var iBeacon = {}; | ||
iBeacon.uuid = data.substr(4,32); | ||
iBeacon.major = data.substr(36,4); | ||
iBeacon.minor = data.substr(40,4); | ||
iBeacon.txPower = pdu.convertTxPower(data.substr(44,2)); | ||
advertiserData.manufacturerSpecificData.iBeacon = iBeacon; | ||
} | ||
/** | ||
* Parse StickNFind 'single payload' manufacturer specific data. | ||
* @param {string} data The manufacturer-specific data as hex string. | ||
* @param {Object} advertiserData The object containing all parsed data. | ||
*/ | ||
function processSnFSingle(data, advertiserData) { | ||
var snfBeacon = {}; | ||
snfBeacon.type = 'V2 Single Payload'; | ||
snfBeacon.id = pdu.reverseBytes(data.substr(2,16)); | ||
snfBeacon.time = parseInt(pdu.reverseBytes(data.substr(18,8)),16); | ||
snfBeacon.scanCount = parseInt(data.substr(26,2),16) / 4; | ||
snfBeacon.batteryVoltage = data.substr(28,2); | ||
snfBeacon.temperature = parseInt(data.substr(30,2),16); | ||
if(snfBeacon.temperature > 127) { | ||
snfBeacon.temperature = 127 - snfBeacon.temperature; | ||
} | ||
snfBeacon.temperature += (parseInt(data.substr(26,2),16) % 4) / 4; | ||
snfBeacon.calibration = data.substr(32,2); | ||
snfBeacon.checksum = data.substr(34,6); | ||
advertiserData.manufacturerSpecificData.snfBeacon = snfBeacon; | ||
} | ||
/** | ||
* Parse StickNSense 'motion' manufacturer specific data. | ||
* @param {string} data The manufacturer-specific data as hex string. | ||
* @param {Object} advertiserData The object containing all parsed data. | ||
*/ | ||
function processSnSMotion(data, advertiserData) { | ||
var snfBeacon = {}; | ||
snfBeacon.type = 'SnS Motion'; | ||
snfBeacon.timestamp = parseInt(pdu.reverseBytes(data.substr(2,8)),16); | ||
snfBeacon.temperature = parseInt(data.substr(10,2),16); | ||
if(snfBeacon.temperature > 127) { | ||
snfBeacon.temperature = 127 - snfBeacon.temperature; | ||
} | ||
snfBeacon.temperature = snfBeacon.temperature / 2; | ||
snfBeacon.temperature += (parseInt(data.substr(41,1),16)) / 4; | ||
snfBeacon.batteryVoltage = data.substr(12,2); | ||
snfBeacon.eventCounters = []; | ||
snfBeacon.eventCounters.push(data.substr(26,1) + data.substr(14,2)); | ||
snfBeacon.eventCounters.push(data.substr(27,1) + data.substr(16,2)); | ||
snfBeacon.eventCounters.push(data.substr(28,1) + data.substr(18,2)); | ||
snfBeacon.eventCounters.push(data.substr(29,1) + data.substr(20,2)); | ||
snfBeacon.eventCounters.push(data.substr(30,1) + data.substr(22,2)); | ||
snfBeacon.eventCounters.push(data.substr(31,1) + data.substr(24,2)); | ||
for(var cCounter = 0; cCounter < 6; cCounter++) { | ||
var hexStringCount = snfBeacon.eventCounters[cCounter]; | ||
snfBeacon.eventCounters[cCounter] = parseInt(hexStringCount,16); | ||
} | ||
snfBeacon.accelerationX = parseInt((data.substr(32,2) + | ||
data.substr(38,1)), 16); | ||
snfBeacon.accelerationY = parseInt((data.substr(34,2) + | ||
data.substr(39,1)), 16); | ||
snfBeacon.accelerationZ = parseInt((data.substr(36,2) + | ||
data.substr(40,1)), 16); | ||
advertiserData.manufacturerSpecificData.snfBeacon = snfBeacon; | ||
} | ||
module.exports.process = process; |
@@ -6,6 +6,9 @@ /** | ||
var pdu = require('../../common/util/pdu.js'); | ||
var gattservices = require('../gatt/services/index.js'); | ||
/** | ||
* Parse BLE advertiser data service data. | ||
/** | ||
* Parse BLE advertiser service data. | ||
* @param {string} payload The raw payload as a hexadecimal-string. | ||
@@ -16,8 +19,12 @@ * @param {number} cursor The start index within the payload. | ||
function process(payload, cursor, advertiserData) { | ||
var serviceData = payload.substr(cursor+4, pdu.getTagDataLength(payload, cursor)); | ||
var serviceData = payload.substr(cursor + 4, | ||
pdu.getTagDataLength(payload, cursor)); | ||
var uuid = serviceData.substr(2,2) + serviceData.substr(0,2); | ||
var data = serviceData.substr(4); | ||
advertiserData.serviceData = { uuid: uuid, data: data }; | ||
gattservices.process(advertiserData); | ||
} | ||
module.exports.process = process; | ||
module.exports.process = process; |
@@ -13,3 +13,3 @@ { | ||
], | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"engines": { | ||
@@ -16,0 +16,0 @@ "node": "^0.10.0" |
@@ -66,2 +66,5 @@ advlib | ||
* [Generic Data](#generic-data) | ||
* [Data](#data-generic-attribute-profile) | ||
* [Member Services](#member-services) | ||
* [Standard Services](#standard-services) | ||
@@ -337,3 +340,9 @@ | ||
##### StickNFind | ||
A specific case of manufacturer specific data is that of StickNFind. The following proprietary payloads are supported: | ||
- V2 Single Payload | ||
- SNS Motion | ||
#### TX Power Level | ||
@@ -455,2 +464,40 @@ | ||
### Data (Generic Attribute Profile) | ||
Process GATT service data (as a hexadecimal string) with the following command: | ||
advlib.ble.data.gatt.process(advData); | ||
Where advData contains a serviceData object (see [Service Data](#service-data)), for instance: | ||
advData: { | ||
serviceData: { | ||
uuid: "fed8", | ||
data: "00f2027265656c7961637469766507" | ||
} | ||
} | ||
Based on the UUID, the serviceData will be parsed as either a member service or a standard service, as applicable. Note that not all services are yet implemented. | ||
#### Member Services | ||
Based on a pilot program for members which allows the SIG to allocate a 16-bit Universally Unique Identifier (UUID) for use with a custom GATT-based service defined by the member. | ||
| UUID | Member | Description | | ||
|-------:|-----------------------|---------------------------------------| | ||
| 0xfed8 | Google | UriBeacon (Physical Web) | | ||
| 0xfeaa | Google | Eddystone | | ||
Supports Eddystone and the UriBeacon of the Physical Web. More documentation to come... | ||
#### Standard Services | ||
Soon to be implemented... | ||
reelyActive RFID Library | ||
@@ -457,0 +504,0 @@ ------------------------ |
@@ -15,9 +15,13 @@ /** | ||
// Inputs for the scenario | ||
var INPUT_DATA_COMPANY_ONLY = '03ff8c00'; | ||
var INPUT_DATA_COMPANY_ONLY = '03ff0800'; | ||
var INPUT_DATA_IBEACON = | ||
'26ff4c000215b9407f30f5f8466eaff925556b57fe6d294c903974'; | ||
var INPUT_DATA_SNF_SINGLE = '17fff9000177665544332211004500000004991800123456'; | ||
var INPUT_DATA_SNS_MOTION = | ||
'18fff90042450000003099001122334455012345aabbccabc0'; | ||
// Expected outputs for the scenario | ||
var EXPECTED_DATA_COMPANY_ONLY = { | ||
companyIdentifierCode: "008c", | ||
companyName: "Motorola", | ||
companyIdentifierCode: "0008", | ||
data: "" | ||
@@ -31,2 +35,22 @@ }; | ||
}; | ||
var EXPECTED_DATA_SNF_SINGLE = { | ||
type: "V2 Single Payload", | ||
id: '0011223344556677', | ||
time: 69, | ||
scanCount: 1, | ||
batteryVoltage: '99', | ||
temperature: 24, | ||
calibration: '00', | ||
checksum: '123456' | ||
}; | ||
var EXPECTED_DATA_SNS_MOTION = { | ||
type: "SnS Motion", | ||
timestamp: 69, | ||
temperature: 24, | ||
batteryVoltage: '99', | ||
eventCounters: [ 0, 273, 546, 819, 1092, 1365 ], | ||
accelerationX: 2730, | ||
accelerationY: 3003, | ||
accelerationZ: 3276 | ||
} | ||
@@ -36,3 +60,3 @@ describe('ble data manufacturerspecificdata', function() { | ||
// Test the process function | ||
it('should convert ble advertiser data to a apple manufacturer specific \ | ||
it('should convert ble advertiser data to a company manufacturer specific \ | ||
data', function() { | ||
@@ -47,8 +71,26 @@ manufacturerspecificdata.process(INPUT_DATA_COMPANY_ONLY, CURSOR, | ||
specificdata', function() { | ||
ADVERTISER_DATA.manufacturerSpecificData.iBeacon = {}; | ||
var advertiserData = { manufacturerSpecificData: {} }; | ||
manufacturerspecificdata.process(INPUT_DATA_IBEACON, CURSOR, | ||
ADVERTISER_DATA); | ||
assert.deepEqual(ADVERTISER_DATA.manufacturerSpecificData.iBeacon, | ||
advertiserData); | ||
assert.deepEqual(advertiserData.manufacturerSpecificData.iBeacon, | ||
EXPECTED_DATA_APPLE_AND_IBEACON); | ||
}); | ||
it('should convert ble advertiser data to StickNFind Beacon Single \ | ||
specificdata', function() { | ||
var advertiserData = { manufacturerSpecificData: {} }; | ||
manufacturerspecificdata.process(INPUT_DATA_SNF_SINGLE, CURSOR, | ||
advertiserData); | ||
assert.deepEqual(advertiserData.manufacturerSpecificData.snfBeacon, | ||
EXPECTED_DATA_SNF_SINGLE); | ||
}); | ||
it('should convert ble advertiser data to StickNSense Motion \ | ||
specificdata', function() { | ||
var advertiserData = { manufacturerSpecificData: {} }; | ||
manufacturerspecificdata.process(INPUT_DATA_SNS_MOTION, CURSOR, | ||
advertiserData); | ||
assert.deepEqual(advertiserData.manufacturerSpecificData.snfBeacon, | ||
EXPECTED_DATA_SNS_MOTION); | ||
}); | ||
}); |
@@ -16,10 +16,15 @@ | ||
var INPUT_DATA = '09160a181204eb150000'; | ||
var INPUT_DATA_COMPANY_NAME = '1216d8fe00f2027265656c7961637469766507'; | ||
// Expected outputs for the scenario | ||
var EXPECTED_DATA ={ | ||
var EXPECTED_DATA = { | ||
uuid: "180a", | ||
data: "1204eb150000", | ||
}; | ||
var EXPECTED_DATA_COMPANY_NAME = { | ||
uuid: "fed8", | ||
data: "00f2027265656c7961637469766507", | ||
companyName: "Google" | ||
} | ||
describe('ble data servicedata', function() { | ||
@@ -32,2 +37,6 @@ | ||
}); | ||
it('should parse BLE advertiser data service data with companyName', function() { | ||
servicedata.process(INPUT_DATA, CURSOR, ADVERTISER_DATA); | ||
assert.deepEqual(ADVERTISER_DATA.serviceData, EXPECTED_DATA); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
149767
88
2337
532