Skip to content

Commit

Permalink
feat: added serial device monitoring to recover from power on->off->on
Browse files Browse the repository at this point in the history
  • Loading branch information
stoprocent committed Feb 26, 2025
1 parent 1149918 commit 11be903
Showing 1 changed file with 72 additions and 25 deletions.
97 changes: 72 additions & 25 deletions lib/uart.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,29 @@ class BluetoothHciSocket extends EventEmitter {
}

bindRaw (devId, params) {
this.bindUser(devId, params);
this._mode = 'raw';
this.bindUser(devId, params, 'raw');
this.reset();
}

bindUser (devId, params) {
this._mode = 'user';
bindUser (devId, params, mode = 'user') {
this._mode = mode;
const uartParams = this._getSerialParams(params);

const { port, baudRate } = uartParams.uart;
if (typeof port === 'string' && Number.isInteger(baudRate)) {
debug(`Using UART PORT = ${port}, BAUD RATE = ${baudRate}`);
const retryConnection = params.retryConnection || 10;
let retryCount = 0;

Check failure on line 53 in lib/uart.js

View workflow job for this annotation

GitHub Actions / lint

'retryCount' is assigned a value but never used

if (typeof port !== 'string' || !Number.isInteger(baudRate)) {
throw new Error('Invalid UART parameters');
}

this._serialDevice = new SerialPort({
debug(`Using UART PORT = ${port}, BAUD RATE = ${baudRate}`);

this._serialDevice = new SerialPort({
path: port,
baudRate,
autoOpen: false,
flowControl: true
});
} else {
throw new Error('Invalid UART parameters');
}
});

if (!this._serialDevice) {
throw new Error('No compatible UART device found!');
Expand All @@ -73,16 +74,55 @@ class BluetoothHciSocket extends EventEmitter {
});
this._queue.pause();

this._parser = this._serialDevice.pipe(new HciSerialParser());
this._parser.on('raw', this.waitForReset.bind(this));
this._hciSerialParser = new HciSerialParser();

this._serialDevice.pipe(this._hciSerialParser);
this._hciSerialParser.on('raw', this.waitForReset.bind(this));

this._serialDevice.on('error', (error) => this.emit('error', error));
this._serialDevice.on('close', () => {
this._isUp = false;
this.emit('state', this._isUp);
this._isUp = false;
this._isReconnectionCancelled = false;
this._serialDevice.unpipe(this._hciSerialParser);
this.emit('state', this._isUp);
this._handleReconnection(devId, params, mode, port, retryConnection);
});
}

async _handleReconnection(devId, params, mode, port, maxRetries) {

Check failure on line 92 in lib/uart.js

View workflow job for this annotation

GitHub Actions / lint

Missing space before function parentheses
let retryCount = 0;
this._isReconnectionCancelled = false; // Reset cancellation flag on new attempt

while (retryCount < maxRetries && !this._isReconnectionCancelled) {
try {
const ports = await SerialPort.list();
const portExists = ports.some(p => p.path === port);

if (portExists) {
debug(`Reconnecting to ${port}`);
this.bindUser(devId, params, mode);
this.start();
this.reset();
return;
}

retryCount++;
debug(`Retry ${retryCount}/${maxRetries} - Port ${port} not found`);
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
} catch (err) {
debug('Error listing ports:', err);
retryCount++;
if (retryCount >= maxRetries || this._isReconnectionCancelled) {
debug(`Reconnection stopped: ${this._isReconnectionCancelled ? 'Cancelled' : `Max retries (${maxRetries}) reached`} for port ${port}`);
return;
}
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second on error
}
}

this._serialDevice.open();
if (!this._isReconnectionCancelled) {
debug(`Max retries (${maxRetries}) reached for port ${port}`);
}
}

_getSerialParams (params) {
Expand Down Expand Up @@ -136,8 +176,8 @@ class BluetoothHciSocket extends EventEmitter {
resetPatterns.some((pattern) => data.includes(pattern))
) {
debug('Reset complete');
this._parser.removeAllListeners('raw');
this._parser.reset();
this._hciSerialParser.removeAllListeners('raw');
this._hciSerialParser.reset();
this._queue.resume();
this._isUp = true;
this.emit('state', this._isUp);
Expand All @@ -153,24 +193,31 @@ class BluetoothHciSocket extends EventEmitter {
throw new Error('Serial device is not initialized');
}

this._serialDevice.open();
this._parser.removeAllListeners('data');
this._parser.on('data', (data) => {
if (!this._serialDevice.isOpen) {
this._serialDevice.open();
}

this._hciSerialParser.removeAllListeners('data');
this._hciSerialParser.on('data', (data) => {
if (this._isUp) {
this.emit('data', data);
}
});
}

stop () {
process.removeListener('exit', this._exitHandler);
if (this._mode !== 'raw' && this._mode !== 'user') {
return;
}
this._parser.removeAllListeners('data');

if (this._serialDevice.isOpen) {
this._serialDevice.close();
this._serialDevice.close();
}

process.removeListener('exit', this._exitHandler);

this._isReconnectionCancelled = true;
this._hciSerialParser.removeAllListeners('data');
this._serialDevice.removeAllListeners();
}

Expand Down

0 comments on commit 11be903

Please sign in to comment.