Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@stoprocent/bluetooth-hci-socket

Package Overview
Dependencies
Maintainers
0
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@stoprocent/bluetooth-hci-socket - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

include/BluetoothHciL2Socket.h

6

examples/le-advertisement-test.js

@@ -149,3 +149,3 @@ const BluetoothHciSocket = require('../index');

cmd.writeUInt8(0x00, 10); // direct addr type
(Buffer.alloc('000000000000', 'hex')).copy(cmd, 11); // direct addr
(Buffer.from('000000000000', 'hex')).copy(cmd, 11); // direct addr
cmd.writeUInt8(0x07, 17);

@@ -223,4 +223,4 @@ cmd.writeUInt8(0x00, 18);

setAdvertisingParameter();
setScanResponseData(Buffer.alloc('0909657374696d6f74650e160a182eb8855fb5ddb601000200', 'hex'));
setAdvertisingData(Buffer.alloc('0201061aff4c000215b9407f30f5f8466eaff925556b57fe6d00010002b6', 'hex'));
setScanResponseData(Buffer.from('0909657374696d6f74650e160a182eb8855fb5ddb601000200', 'hex'));
setAdvertisingData(Buffer.from('0201061aff4c000215b9407f30f5f8466eaff925556b57fe6d00010002b6', 'hex'));
setAdvertiseEnable(true);

@@ -57,3 +57,3 @@ const BluetoothHciSocket = require('../index');

writeHandle(handle, Buffer.alloc('020001', 'hex'));
writeHandle(handle, Buffer.from('020001', 'hex'));
}

@@ -147,3 +147,3 @@ }

cmd.writeUInt8(addressType === 'random' ? 0x01 : 0x00, 9); // peer address type
(Buffer.alloc(address.split(':').reverse().join(''), 'hex')).copy(cmd, 10); // peer address
(Buffer.from(address.split(':').reverse().join(''), 'hex')).copy(cmd, 10); // peer address

@@ -150,0 +150,0 @@ cmd.writeUInt8(0x00, 16); // own address type

@@ -1,4 +0,2 @@

const events = require('events');
const util = require('util');
const EventEmitter = require('events');
const debug = require('debug')('hci-uart');

@@ -10,181 +8,178 @@ const { SerialPort } = require('serialport');

const HCI_COMMAND_PKT = 0x01;
// eslint-disable-next-line no-unused-vars
const HCI_ACLDATA_PKT = 0x02;
// eslint-disable-next-line no-unused-vars
const HCI_EVENT_PKT = 0x04;
const OGF_HOST_CTL = 0x03;
const OCF_RESET = 0x0003;
const OCF_SET_EVENT_FILTER = 0x0005;
const SET_EVENT_FILTER_CMD = OCF_SET_EVENT_FILTER | OGF_HOST_CTL << 10;
const SET_EVENT_FILTER_CMD = OCF_SET_EVENT_FILTER | (OGF_HOST_CTL << 10);
const RESET_CMD = OCF_RESET | (OGF_HOST_CTL << 10);
function BluetoothHciSocket (useFilter = false) {
this._isUp = false;
this._reset = null;
this._useFilter = useFilter;
}
class BluetoothHciSocket extends EventEmitter {
constructor (useFilter = false) {
super();
this._isUp = false;
this._useFilter = useFilter;
this._mode = null;
this._serialDevice = null;
this._queue = null;
this._parser = null;
}
util.inherits(BluetoothHciSocket, events.EventEmitter);
setFilter (filter) {
if (!this._useFilter) {
return;
}
BluetoothHciSocket.prototype.setFilter = function (filter) {
if (this._useFilter === false) {
return;
const header = Buffer.alloc(4);
header.writeUInt8(HCI_COMMAND_PKT, 0);
header.writeUInt16LE(SET_EVENT_FILTER_CMD, 1);
header.writeUInt8(filter.length, 3);
const cmd = Buffer.concat([header, filter]);
this.write(cmd);
}
// Filter Header
let cmd = Buffer.alloc(4);
cmd.writeUInt8(HCI_COMMAND_PKT, 0);
cmd.writeUInt16LE(SET_EVENT_FILTER_CMD, 1);
// Length
cmd.writeUInt8(filter.length, 3);
bindRaw (devId, params) {
this.bindUser(devId, params);
this._mode = 'raw';
this.reset();
}
// Concate Buffers
cmd = Buffer.concat([cmd, filter]);
bindUser (devId, params) {
this._mode = 'user';
const uartParams = this._getSerialParams(params);
this.write(cmd);
};
const { port, baudRate } = uartParams.uart;
if (typeof port === 'string' && Number.isInteger(baudRate)) {
debug(`Using UART PORT = ${port}, BAUD RATE = ${baudRate}`);
BluetoothHciSocket.prototype.bindRaw = function (devId, params) {
this.bindUser(devId, params);
this._serialDevice = new SerialPort({
path: port,
baudRate,
autoOpen: false,
flowControl: true
});
} else {
throw new Error('Invalid UART parameters');
}
this._mode = 'raw';
if (!this._serialDevice) {
throw new Error('No compatible UART device found!');
}
this.reset();
};
this._queue = async.queue((data, callback) => {
this._serialDevice.write(data, callback);
});
this._queue.pause();
BluetoothHciSocket.prototype.bindUser = function (devId, params) {
this._mode = 'user';
this._parser = this._serialDevice.pipe(new HciSerialParser());
this._parser.on('raw', this.waitForReset.bind(this));
const uartParams = this._getSerialParams(params);
if ((typeof uartParams.uart.port === 'string' || uartParams.uart.port instanceof String) && Number.isInteger(uartParams.uart.baudRate)) {
debug('using UART PORT = ' + uartParams.uart.port + ', BAUD RATE = ' + uartParams.uart.baudRate);
this._serialDevice = new SerialPort({
path: uartParams.uart.port,
baudRate: uartParams.uart.baudRate,
autoOpen: false,
flowControl: true
this._serialDevice.on('error', (error) => this.emit('error', error));
this._serialDevice.on('close', () => {
this._isUp = false;
this.emit('state', this._isUp);
});
}
if (!this._serialDevice) {
throw new Error('No compatible UART device found!');
this._serialDevice.open();
}
// Message Queue
this._queue = async.queue((data, callback) => this._serialDevice.write(data, (a, b) => callback()));
this._queue.pause();
_getSerialParams (params) {
let port;
let baudRate = 1000000; // Default baud rate
// Serial Port Parser
this._parser = this._serialDevice.pipe(new HciSerialParser());
this._parser.on('raw', this.waitForReset.bind(this));
// Check for UART port in environment variables
if (process.env.BLUETOOTH_HCI_SOCKET_UART_PORT) {
port = process.env.BLUETOOTH_HCI_SOCKET_UART_PORT;
}
// Serial Port Event Listeners
this._serialDevice.on('error', error => this.emit('error', error));
this._serialDevice.on('close', () => {
this.isDevUp = false;
this.emit('state', this._isUp);
});
// Check for UART baud rate in environment variables
if (process.env.BLUETOOTH_HCI_SOCKET_UART_BAUDRATE) {
const parsedBaudRate = parseInt(process.env.BLUETOOTH_HCI_SOCKET_UART_BAUDRATE, 10);
if (!isNaN(parsedBaudRate)) {
baudRate = parsedBaudRate;
}
}
// Open Serial Port to begin
this._serialDevice.open();
};
BluetoothHciSocket.prototype._getSerialParams = function (params) {
const uartParams = {
uart: {
port: undefined, baudRate: 1000000
// Override with params if provided
if (params && params.uart) {
if (params.uart.port && typeof params.uart.port === 'string') {
port = params.uart.port;
}
if (params.uart.baudRate && typeof params.uart.baudRate === 'number' && isFinite(params.uart.baudRate)) {
baudRate = params.uart.baudRate;
}
}
};
if (process.env.BLUETOOTH_HCI_SOCKET_UART_PORT) {
uartParams.uart.port = process.env.BLUETOOTH_HCI_SOCKET_UART_PORT;
return { uart: { port, baudRate } };
}
if (process.env.BLUETOOTH_HCI_SOCKET_UART_BAUDRATE) {
uartParams.uart.baudRate = parseInt(process.env.BLUETOOTH_HCI_SOCKET_UART_BAUDRATE, 10);
bindControl () {
this._mode = 'control';
}
if (params && params.uart) {
if (params.uart.port instanceof String || typeof params.uart.port === 'string') {
uartParams.uart.port = params.uart.port;
}
if (Number.isInteger(params.uart.baudRate)) {
uartParams.uart.baudRate = params.uart.baudRate;
}
isDevUp () {
return this._isUp;
}
return uartParams;
};
waitForReset (data) {
const resetPatterns = [
Buffer.from('040e0401030c00', 'hex'),
Buffer.from('040e0402030c00', 'hex'),
Buffer.from('040e0405030c00', 'hex')
];
BluetoothHciSocket.prototype.bindControl = function () {
this._mode = 'control';
};
BluetoothHciSocket.prototype.isDevUp = function () {
return this._isUp;
};
BluetoothHciSocket.prototype.waitForReset = function (data) {
// Handle Reset
if (this._isUp === false && this._mode === 'raw' && (data.includes(Buffer.from('040e0401030c00', 'hex')) || data.includes(Buffer.from('040e0402030c00', 'hex')) || data.includes(Buffer.from('040e0405030c00', 'hex')))) {
debug('reset complete');
// Remove this listener
this._parser.removeAllListeners('raw');
// Reset parser just in case we have noisy data
this._parser.reset();
// Resume other writes
this._queue.resume();
// Mark UP
this._isUp = true;
this.emit('state', this._isUp);
if (
!this._isUp &&
this._mode === 'raw' &&
resetPatterns.some((pattern) => data.includes(pattern))
) {
debug('Reset complete');
this._parser.removeAllListeners('raw');
this._parser.reset();
this._queue.resume();
this._isUp = true;
this.emit('state', this._isUp);
}
}
};
BluetoothHciSocket.prototype.start = function () {
if (this._mode === 'raw' || this._mode === 'user') {
// Cleanup
this._parser.removeAllListeners('data');
// Register
this._parser.on('data', (data) => {
// Skip the first reset
if (this._isUp === true) {
// Emit Data Event on HCI
this.emit('data', data);
}
});
start () {
if (this._mode === 'raw' || this._mode === 'user') {
this._parser.removeAllListeners('data');
this._parser.on('data', (data) => {
if (this._isUp) {
this.emit('data', data);
}
});
}
}
};
BluetoothHciSocket.prototype.stop = function () {
if (this._mode === 'raw' || this._mode === 'user') {
this._parser.removeAllListeners('data');
stop () {
if (this._mode === 'raw' || this._mode === 'user') {
this._parser.removeAllListeners('data');
}
}
};
BluetoothHciSocket.prototype.write = function (data) {
debug('write: ' + data.toString('hex'));
if (this._mode === 'raw' || this._mode === 'user') {
this._queue.push(data);
write (data) {
debug(`Write: ${data.toString('hex')}`);
if (this._mode === 'raw' || this._mode === 'user') {
this._queue.push(data);
}
}
};
BluetoothHciSocket.prototype.reset = function () {
const cmd = Buffer.alloc(4);
reset () {
if (!this._serialDevice) {
throw new Error('Serial device is not initialized');
}
// header
cmd.writeUInt8(HCI_COMMAND_PKT, 0);
cmd.writeUInt16LE(RESET_CMD, 1);
const cmd = Buffer.alloc(4);
cmd.writeUInt8(HCI_COMMAND_PKT, 0);
cmd.writeUInt16LE(RESET_CMD, 1);
cmd.writeUInt8(0x00, 3);
// length
cmd.writeUInt8(0x00, 3);
debug(`Reset: ${cmd.toString('hex')}`);
this._serialDevice.write(cmd);
}
}
debug('reset:', cmd.toString('hex'));
this._serialDevice.write(cmd);
};
module.exports = BluetoothHciSocket;

@@ -10,12 +10,11 @@ const debug = require('debug')('hci-serial-parser');

constructor (options) {
super();
super(options);
this.reset();
}
_transform (chunk, encoding, cb) {
_transform (chunk, encoding, callback) {
this.packetData = Buffer.concat([this.packetData, chunk]);
debug('HciPacketParser._transform:', this.packetData.toString('hex'));
debug('HciPacketParser._transform: ', this.packetData.toString('hex'));
if (this.packetType === -1) {
if (this.packetType === -1 && this.packetData.length > 0) {
this.packetType = this.packetData.readUInt8(0);

@@ -28,19 +27,18 @@ }

let skipPacket = false;
while (this.packetData.length >= this.packetSize + this.prePacketSize && !skipPacket) {
if (this.packetSize === 0 && (this.packetType === HCI_EVENT_PKT || this.packetType === HCI_COMMAND_PKT) && this.packetData.length >= 3) {
this.packetSize = this.packetData.readUInt8(2);
this.prePacketSize = 3;
} else if (this.packetSize === 0 && this.packetType === HCI_ACLDATA_PKT && this.packetData.length >= 5) {
this.packetSize = this.packetData.readUInt16LE(3);
this.prePacketSize = 5;
while (this.packetData.length > 0) {
if (this.packetSize === 0) {
if (!this._determinePacketSize()) {
break;
}
}
if (this.packetData.length < this.packetSize + this.prePacketSize || this.packetSize === 0) {
skipPacket = true; continue;
if (this.packetData.length < this.prePacketSize + this.packetSize) {
break;
}
this.push(this.packetData.subarray(0, this.packetSize + this.prePacketSize));
const packet = this.packetData.slice(0, this.prePacketSize + this.packetSize);
this.push(packet);
this.packetData = this.packetData.subarray(this.packetSize + this.prePacketSize);
this.packetData = this.packetData.slice(this.prePacketSize + this.packetSize);
this.packetType = -1;
this.packetSize = 0;

@@ -55,16 +53,44 @@ this.prePacketSize = 0;

}
cb();
callback();
}
_determinePacketSize () {
if (this.packetData.length < 1) {
return false;
}
const packetType = this.packetData.readUInt8(0);
if (packetType === HCI_EVENT_PKT || packetType === HCI_COMMAND_PKT) {
if (this.packetData.length >= 3) {
this.prePacketSize = 3;
this.packetSize = this.packetData.readUInt8(2);
return true;
}
} else if (packetType === HCI_ACLDATA_PKT) {
if (this.packetData.length >= 5) {
this.prePacketSize = 5;
this.packetSize = this.packetData.readUInt16LE(3);
return true;
}
} else {
this.emit('error', new Error(`Unknown packet type: ${packetType}`));
}
return false;
}
reset () {
this.packetData = Buffer.alloc(0);
this.packetType = -1;
this.packetSize = 0;
this.prePacketSize = 0;
this.packetType = -1;
this.packetData = Buffer.alloc(0);
}
_flush (cb) {
this.emit('raw', this.packetData);
_flush (callback) {
if (this.listenerCount('raw') > 0 && this.packetData.length > 0) {
this.emit('raw', this.packetData);
}
this.reset();
cb();
callback();
}

@@ -71,0 +97,0 @@ }

{
"name": "@stoprocent/bluetooth-hci-socket",
"version": "1.2.1",
"version": "1.3.0",
"description": "Bluetooth HCI socket binding for Node.js",

@@ -34,32 +34,37 @@ "main": "index.js",

"dependencies": {
"debug": "^4.3.4",
"nan": "^2.17.0",
"node-addon-api": "^4.3.0",
"node-gyp-build": "^4.6.1",
"async": "^3.2.4",
"serialport": "^12.0.0"
"debug": "^4.3.7",
"node-addon-api": "^8.1.0",
"node-gyp-build": "^4.8.1",
"async": "^3.2.6",
"serialport": "^12.0.0",
"patch-package": "^8.0.0"
},
"optionalDependencies": {
"usb": "^1.9.2"
"usb": "^2.14.0"
},
"devDependencies": {
"@semantic-release/exec": "6.0.3",
"eslint": "^8.31.0",
"eslint-config-semistandard": "^17.0.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.6.0",
"eslint-plugin-promise": "^6.1.1",
"jshint": "^2.13.6",
"node-gyp": "^10.0.0",
"prebuildify": "^5.0.1",
"prebuildify-cross": "5.0.0",
"semantic-release": "21.1.0"
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^10.1.1",
"eslint": "^8.57.1",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-n": "^17.10.3",
"eslint-plugin-promise": "^7.1.0",
"mocha": "^10.7.0",
"nyc": "^17.0.0",
"prebuildify": "^6.0.1",
"prebuildify-cross": "^5.1.0",
"semantic-release": "^24.1.1",
"jshint": "^2.13.6"
},
"scripts": {
"install": "node-gyp-build",
"postinstall": "patch-package",
"lint": "eslint \"**/*.js\"",
"lint-fix": "eslint \"**/*.js\" --fix",
"prebuildify": "prebuildify --napi --target 14.0.0 --force --strip --verbose",
"prebuildify-cross": "prebuildify-cross --napi --target 14.0.0 --force --strip --verbose",
"prebuildify": "prebuildify --napi --target 17.0.0 --force --strip --verbose",
"prebuildify-cross": "prebuildify-cross --napi --target 17.0.0 --force --strip --verbose",
"semantic-release": "semantic-release",

@@ -66,0 +71,0 @@ "pretest": "npm run rebuild",

# node-bluetooth-hci-socket
[![GitHub forks](
https://img.shields.io/github/forks/abandonware/node-bluetooth-hci-socket.svg?style=social&label=Fork&maxAge=2592000
https://img.shields.io/github/forks/stoprocent/node-bluetooth-hci-socket.svg?style=social&label=Fork&maxAge=2592000
)](
https://GitHub.com/abandonware/node-bluetooth-hci-socket/network/
https://GitHub.com/stoprocent/node-bluetooth-hci-socket/network/
)

@@ -12,5 +12,5 @@ [![license](

[![NPM](
https://img.shields.io/npm/v/@abandonware/bluetooth-hci-socket.svg
https://img.shields.io/npm/v/@stoprocent/bluetooth-hci-socket.svg
)](
https://www.npmjs.com/package/@abandonware/bluetooth-hci-socket
https://www.npmjs.com/package/@stoprocent/bluetooth-hci-socket
)

@@ -30,3 +30,3 @@ [![Fediverse](

__NOTE:__ Currently only supports __Linux__, __FreeBSD__ and __Windows__.
__NOTE:__ Currently only supports __Linux__, __FreeBSD__, __Windows__ or any operating systems when using HCI over uart.

@@ -93,3 +93,3 @@ ## Prerequisites

```sh
npm install @abandonware/bluetooth-hci-socket
npm install @stoprocent/bluetooth-hci-socket
```

@@ -100,3 +100,3 @@

```javascript
var BluetoothHciSocket = require('@abandonware/bluetooth-hci-socket');
var BluetoothHciSocket = require('@stoprocent/bluetooth-hci-socket');
```

@@ -207,3 +207,3 @@

See [examples folder](https://github.com/abandonware/node-bluetooth-hci-socket/blob/master/examples) for code examples.
See [examples folder](https://github.com/stoprocent/node-bluetooth-hci-socket/blob/master/examples) for code examples.

@@ -210,0 +210,0 @@ ## Platform Notes

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc