UNPKG

@stoprocent/bluetooth-hci-socket

Version:
170 lines (130 loc) 4.85 kB
const BluetoothHciSocket = require('../index'); const bluetoothHciSocket = new BluetoothHciSocket(); bluetoothHciSocket.on('data', function (data) { console.log('data: ' + data.toString('hex')); if (data.readUInt8(0) === HCI_EVENT_PKT) { if (data.readUInt8(1) === EVT_CMD_COMPLETE) { if (data.readUInt16LE(4) === LE_SET_SCAN_PARAMETERS_CMD) { if (data.readUInt8(6) === HCI_SUCCESS) { console.log('LE Scan Parameters Set'); } } else if (data.readUInt16LE(4) === LE_SET_SCAN_ENABLE_CMD) { if (data.readUInt8(6) === HCI_SUCCESS) { console.log('LE Scan Enable Set'); } } } else if (data.readUInt8(1) === EVT_LE_META_EVENT) { if (data.readUInt8(3) === EVT_LE_ADVERTISING_REPORT) { // subevent const gapAdvType = data.readUInt8(5); const gapAddrType = data.readUInt8(6); const gapAddr = data.slice(7, 13); const eir = data.slice(14, data.length - 1); const rssi = data.readInt8(data.length - 1); console.log('LE Advertising Report'); console.log('\t' + ['ADV_IND', 'ADV_DIRECT_IND', 'ADV_SCAN_IND', 'ADV_NONCONN_IND', 'SCAN_RSP'][gapAdvType]); console.log('\t' + ['PUBLIC', 'RANDOM'][gapAddrType]); console.log('\t' + gapAddr.toString('hex').match(/.{1,2}/g).reverse().join(':')); console.log('\t' + eir.toString('hex')); console.log('\t' + rssi); } } } }); bluetoothHciSocket.on('error', function (error) { // TODO: non-BLE adaptor if (error.message === 'Operation not permitted') { console.log('state = unauthorized'); } else if (error.message === 'Network is down') { console.log('state = powered off'); } else { console.error(error); } }); const HCI_COMMAND_PKT = 0x01; // eslint-disable-next-line no-unused-vars const HCI_ACLDATA_PKT = 0x02; const HCI_EVENT_PKT = 0x04; const OGF_HOST_CTL = 0x03; const EVT_CMD_COMPLETE = 0x0e; const EVT_CMD_STATUS = 0x0f; const EVT_LE_META_EVENT = 0x3e; const EVT_LE_ADVERTISING_REPORT = 0x02; const OGF_LE_CTL = 0x08; const OCF_LE_SET_SCAN_PARAMETERS = 0x000b; const OCF_LE_SET_SCAN_ENABLE = 0x000c; const OCF_SET_EVENT_MASK = 0x0001; const OCF_LE_SET_EVENT_MASK = 0x0001; const LE_SET_SCAN_PARAMETERS_CMD = OCF_LE_SET_SCAN_PARAMETERS | OGF_LE_CTL << 10; const LE_SET_SCAN_ENABLE_CMD = OCF_LE_SET_SCAN_ENABLE | OGF_LE_CTL << 10; const SET_EVENT_MASK_CMD = OCF_SET_EVENT_MASK | (OGF_HOST_CTL << 10); const LE_SET_EVENT_MASK_CMD = OCF_LE_SET_EVENT_MASK | (OGF_LE_CTL << 10); const HCI_SUCCESS = 0; function setEventMask () { const cmd = Buffer.alloc(12); const eventMask = Buffer.from('fffffbff07f8bf3d', 'hex'); // header cmd.writeUInt8(HCI_COMMAND_PKT, 0); cmd.writeUInt16LE(SET_EVENT_MASK_CMD, 1); // length cmd.writeUInt8(eventMask.length, 3); eventMask.copy(cmd, 4); bluetoothHciSocket.write(cmd); } function setLeEventMask () { const cmd = Buffer.alloc(12); const leEventMask = Buffer.from('1fff000000000000', 'hex'); // header cmd.writeUInt8(HCI_COMMAND_PKT, 0); cmd.writeUInt16LE(LE_SET_EVENT_MASK_CMD, 1); // length cmd.writeUInt8(leEventMask.length, 3); leEventMask.copy(cmd, 4); bluetoothHciSocket.write(cmd); } function setFilter () { const filter = Buffer.alloc(14); const typeMask = (1 << HCI_EVENT_PKT); const eventMask1 = (1 << EVT_CMD_COMPLETE) | (1 << EVT_CMD_STATUS); const eventMask2 = (1 << (EVT_LE_META_EVENT - 32)); const opcode = 0; filter.writeUInt32LE(typeMask, 0); filter.writeUInt32LE(eventMask1, 4); filter.writeUInt32LE(eventMask2, 8); filter.writeUInt16LE(opcode, 12); bluetoothHciSocket.setFilter(filter); } function setScanParameters () { const cmd = Buffer.alloc(11); // header cmd.writeUInt8(HCI_COMMAND_PKT, 0); cmd.writeUInt16LE(LE_SET_SCAN_PARAMETERS_CMD, 1); // length cmd.writeUInt8(0x07, 3); // data cmd.writeUInt8(0x01, 4); // type: 0 -> passive, 1 -> active cmd.writeUInt16LE(0x0010, 5); // internal, ms * 1.6 cmd.writeUInt16LE(0x0010, 7); // window, ms * 1.6 cmd.writeUInt8(0x00, 9); // own address type: 0 -> public, 1 -> random cmd.writeUInt8(0x00, 10); // filter: 0 -> all event types bluetoothHciSocket.write(cmd); } function setScanEnable (enabled, duplicates) { const cmd = Buffer.alloc(6); // header cmd.writeUInt8(HCI_COMMAND_PKT, 0); cmd.writeUInt16LE(LE_SET_SCAN_ENABLE_CMD, 1); // length cmd.writeUInt8(0x02, 3); // data cmd.writeUInt8(enabled ? 0x01 : 0x00, 4); // enable: 0 -> disabled, 1 -> enabled cmd.writeUInt8(duplicates ? 0x01 : 0x00, 5); // duplicates: 0 -> no duplicates, 1 -> duplicates bluetoothHciSocket.write(cmd); } bluetoothHciSocket.bindRaw(); setFilter(); bluetoothHciSocket.start(); setEventMask(); setLeEventMask(); setScanEnable(false, true); setScanParameters(); setScanEnable(true, true);