UNPKG

barnowl-huawei

Version:

Collect ambient Bluetooth Low Energy packets from Huawei access points for real-time location and sensing. We believe in an open Internet of Things.

98 lines (75 loc) 3.02 kB
/** * Copyright reelyActive 2021 * We believe in an open Internet of Things */ const advlib = require('advlib-identifier'); const Raddec = require('raddec'); const MINIMUM_FRAME_LENGTH = 26; const HUAWEI_VENDOR_ID = 0x4857; /** * Determine if the given data begins with the Huawei vendor ID. * @param {Buffer} data The binary packet as a buffer. */ function isValidHuawei(data) { let isHuaweiVendorId = (data.readUInt16BE(0) === HUAWEI_VENDOR_ID); return isHuaweiVendorId; } /** * Decode a single transmitter frame from the given buffer and offset. * @param {Buffer} data The binary packet as a buffer. * @param {Number} index The byte index of the start of the transmitter frame. * @param {Array} raddecs The array of raddecs. * @param {String} receiverId The identifier of the receiver. * @param {Number} timestamp The optional timestamp override of the decoding. */ function decodeTransmitterFrame(data, index, raddecs, receiverId, timestamp) { timestamp = timestamp || data.readUInt32BE(index + 6) * 1000; let transmitterId = ('00000000000' + data.readUIntBE(index, 6).toString(16)).substr(-12); let transmitterIdLittleEndian = data.readUIntLE(index, 6).toString(16); let rssi = data.readInt8(index + 10); let packetLength = data.readUInt8(index + 13); let packetFrameIndex = index + 14 + packetLength; let raddec = new Raddec({ transmitterId: transmitterId, transmitterIdType: Raddec.identifiers.TYPE_EUI48, // TODO: unknown timestamp: timestamp }); raddec.addDecoding({ receiverId: receiverId, receiverIdType: Raddec.identifiers.TYPE_EUI48, rssi: rssi }); if(packetLength > 0) { let packet = ('000' + packetLength.toString(16)).substr(-4); packet += transmitterIdLittleEndian; packet += data.toString('hex', index + 14, packetFrameIndex); raddec.addPacket(packet); } raddecs.push(raddec); return packetFrameIndex; } /** * Decode all the serial packets from the hex string. * @param {Buffer} data The binary packet as a buffer. * @param {String} origin Origin of the data stream. * @param {Number} time The time of the data capture. * @param {Object} options The packet decoding options. */ function decode(data, origin, time, options) { let raddecs = []; let isTooShort = (data.length < MINIMUM_FRAME_LENGTH); if(isTooShort || !isValidHuawei(data)) { return raddecs; } let receiverId = data.readUIntBE(3,6).toString(16); let numberOfTransmitters = data.readUInt8(11); let transmitterFrameIndex = 12; let timestamp = (options.timestampOnArrival ? time : null); for(let cTransmitter = 0; cTransmitter < numberOfTransmitters; cTransmitter++) { transmitterFrameIndex = decodeTransmitterFrame(data, transmitterFrameIndex, raddecs, receiverId, timestamp); } return raddecs; } module.exports.decode = decode;