Skip to content

Commit

Permalink
fix: linux app crashing
Browse files Browse the repository at this point in the history
  • Loading branch information
irshadjsr21 committed Dec 1, 2023
1 parent 7c0c6cc commit 9fa8c3a
Show file tree
Hide file tree
Showing 5 changed files with 952 additions and 94 deletions.
5 changes: 5 additions & 0 deletions .changeset/nice-humans-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@cypherock/sdk-hw-hid': patch
---

fix linux app crashing
3 changes: 1 addition & 2 deletions packages/hw-hid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"@cypherock/eslint-config": "workspace:*",
"@cypherock/prettier-config": "workspace:^0.0.7",
"@cypherock/tsconfig": "workspace:*",
"@types/node-hid": "^1.3.1",
"@types/uuid": "^9.0.0",
"eslint": "^7.32.0",
"lint-staged": "^13.2.0",
Expand All @@ -26,7 +25,7 @@
"dependencies": {
"@cypherock/sdk-interfaces": "workspace:^0.0.14",
"@cypherock/sdk-utils": "workspace:^",
"node-hid": "^2.1.2",
"node-hid": "^3.0.0",
"usb": "^2.11.0",
"uuid": "^9.0.0"
},
Expand Down
30 changes: 22 additions & 8 deletions packages/hw-hid/src/deviceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ import HID from 'node-hid';
import * as uuid from 'uuid';

import { getAvailableDevices, DataListener } from './helpers';

import { logger } from './logger';

export default class DeviceConnection implements IDeviceConnection {
protected connectionId: string;

protected sequenceNumber: number;

protected connection: HID.HID;
protected connection: HID.HIDAsync;

protected initialized: boolean;

Expand All @@ -28,14 +27,14 @@ export default class DeviceConnection implements IDeviceConnection {

private readonly device: IDevice;

constructor(device: IDevice) {
constructor(device: IDevice, connection: HID.HIDAsync) {
this.device = { ...device };
this.connectionId = uuid.v4();
this.sequenceNumber = 0;

this.connection = new HID.HID(this.device.path);
this.initialized = true;
this.isPortOpen = true;
this.connection = connection;
this.dataListener = new DataListener({
device: this.device,
connection: this.connection,
Expand All @@ -49,7 +48,8 @@ export default class DeviceConnection implements IDeviceConnection {
}

public static async connect(device: IDevice) {
return new DeviceConnection(device);
const connection = await HID.HIDAsync.open(device.path);
return new DeviceConnection(device, connection);
}

public static async list() {
Expand All @@ -62,7 +62,8 @@ export default class DeviceConnection implements IDeviceConnection {
if (devices.length <= 0)
throw new DeviceConnectionError(DeviceConnectionErrorType.NOT_CONNECTED);

return new DeviceConnection(devices[0]);
const connection = await HID.HIDAsync.open(devices[0].path);
return new DeviceConnection(devices[0], connection);
}

public static async getAvailableConnection() {
Expand Down Expand Up @@ -98,7 +99,15 @@ export default class DeviceConnection implements IDeviceConnection {
* Destroyes the connection and stop listening to the data.
*/
public async destroy() {
this.dataListener.destroy();
if (!this.isPortOpen) return;

await this.dataListener.destroy();
try {
await this.connection.close();
} catch (error) {
logger.warn('Error while closing device connection');
logger.warn(error);
}
}

/**
Expand All @@ -121,7 +130,12 @@ export default class DeviceConnection implements IDeviceConnection {
* Writes a given data string (in hex) to the device.
*/
public async send(data: Uint8Array) {
this.connection.write(Buffer.from([0x00, ...data]));
const dataToWrite = [
0x00,
...data,
...new Array(64 - data.length).fill(0x00),
];
await this.connection.write(Buffer.from(dataToWrite));
}

public async receive() {
Expand Down
61 changes: 53 additions & 8 deletions packages/hw-hid/src/helpers/dataListeners.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import HID from 'node-hid';
import * as HID from 'node-hid';
import * as uuid from 'uuid';
import { usb } from 'usb';
import { IDevice, PoolData } from '@cypherock/sdk-interfaces';
import { getAvailableDevices } from './connection';
import { logger } from '../logger';

// eslint-disable-next-line
export class DataListener {
private readonly connection: HID.HID;
private readonly connection: HID.HIDAsync;

private readonly device: IDevice;

Expand All @@ -20,8 +21,12 @@ export class DataListener {

private readonly onSomeDeviceDisconnectBinded: (device: usb.Device) => void;

private readTimeoutId: NodeJS.Timeout | undefined;

private readPromise: Promise<void> | undefined;

constructor(params: {
connection: HID.HID;
connection: HID.HIDAsync;
device: IDevice;
onClose?: () => void;
onError?: (err: Error) => void;
Expand All @@ -37,9 +42,15 @@ export class DataListener {
this.startListening();
}

public destroy() {
public async destroy() {
if (this.readPromise) {
await this.readPromise;
}

this.stopListening();
this.connection.close();
if (this.onCloseCallback) {
this.onCloseCallback();
}
}

public isListening() {
Expand All @@ -54,13 +65,21 @@ export class DataListener {
return [...this.pool];
}

private clearReadInterval() {
if (this.readTimeoutId) clearTimeout(this.readTimeoutId);
}

private setReadInterval() {
this.readTimeoutId = setTimeout(this.onRead.bind(this), 0);
}

/**
* Starts listening to all the events
*/
private startListening() {
this.listening = true;

this.connection.addListener('data', this.onData.bind(this));
this.setReadInterval();
this.connection.addListener('close', this.onClose.bind(this));
this.connection.addListener('error', this.onError.bind(this));

Expand All @@ -71,7 +90,8 @@ export class DataListener {
* Stop listening to all the events
*/
private stopListening() {
this.connection.removeListener('data', this.onData.bind(this));
this.clearReadInterval();

this.connection.removeListener('close', this.onClose.bind(this));
this.connection.removeListener('error', this.onError.bind(this));
this.connection.removeAllListeners();
Expand All @@ -80,11 +100,36 @@ export class DataListener {
this.listening = false;
}

private async onRead() {
if (!this.listening) {
this.clearReadInterval();
return;
}

let resolvePromise: (() => void) | undefined;

this.readPromise = new Promise(resolve => {
resolvePromise = resolve;
});

try {
const data = await this.connection.read(300);
this.onData(data as any);
} catch (error) {
logger.error('Error while reading data from device');
logger.error(error);
} finally {
if (resolvePromise) resolvePromise();
this.setReadInterval();
}
}

private async onData(data: Buffer) {
this.pool.push({ id: uuid.v4(), data: Uint8Array.from(data) });
}

private async onClose() {
this.stopListening();
if (this.onCloseCallback) {
this.onCloseCallback();
}
Expand All @@ -110,8 +155,8 @@ export class DataListener {
);

if (!isDeviceConnected) {
await this.destroy();
this.onClose();
this.destroy();
}
}
}
Loading

0 comments on commit 9fa8c3a

Please sign in to comment.