Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve serialport code consistency across adapters. #859

Merged
merged 4 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 41 additions & 36 deletions src/adapter/deconz/driver/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ class Driver extends events.EventEmitter {
return paths.length > 0 ? paths[0] : null;
}

private onPortError(error: Error): void {
debug(`Port error: ${error}`);
}

private onPortClose(): void {
debug('Port closed');
this.initialized = false;
Expand All @@ -184,7 +188,7 @@ class Driver extends events.EventEmitter {
return this.portType === 'serial' ? this.openSerialPort(baudrate) : this.openSocketPort();
}

public openSerialPort(baudrate: number): Promise<void> {
private async openSerialPort(baudrate: number): Promise<void> {
debug(`Opening with ${this.path}`);
this.serialPort = new SerialPort({path: this.path, baudRate: baudrate, autoOpen: false}); //38400 RaspBee //115200 ConBee3

Expand All @@ -196,21 +200,24 @@ class Driver extends events.EventEmitter {
this.serialPort.pipe(this.parser);
this.parser.on('parsed', this.onParsed);

return new Promise((resolve, reject): void => {
this.serialPort.open(async (error: object): Promise<void> => {
if (error) {
reject(new Error(`Error while opening serialport '${error}'`));
this.initialized = false;
if (this.serialPort.isOpen) {
this.serialPort.close();
}
} else {
debug('Serialport opened');
this.initialized = true;
resolve();
}
});
});
try {
await this.serialPort.asyncOpen();
debug('Serialport opened');

this.serialPort.once('close', this.onPortClose.bind(this));
this.serialPort.once('error', this.onPortError.bind(this));

this.initialized = true;
this.emit('connected');
} catch (error) {
this.initialized = false;

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

throw error;
}
}

private async openSocketPort(): Promise<void> {
Expand Down Expand Up @@ -240,7 +247,7 @@ class Driver extends events.EventEmitter {
resolve();
});

this.socketPort.once('close', this.onPortClose);
this.socketPort.once('close', this.onPortClose.bind(this));

this.socketPort.on('error', function () {
debug('Socket error');
Expand All @@ -252,29 +259,27 @@ class Driver extends events.EventEmitter {
});
}

public close(): Promise<void> {
return new Promise((resolve, reject): void => {
if (this.initialized) {
if (this.portType === 'serial') {
this.serialPort.flush((): void => {
this.serialPort.close((error): void => {
this.initialized = false;
error == null ?
resolve() :
reject(new Error(`Error while closing serialport '${error}'`));
this.emit('close');
});
});
} else {
this.socketPort.destroy();
resolve();
public async close(): Promise<void> {
debug('closing');
queue = [];

if (this.initialized) {
this.initialized = false;

if (this.portType === 'serial') {
try {
await this.serialPort.asyncFlushAndClose();
} catch (error) {
this.emit('close');

throw error;
}
} else {
resolve();
this.emit('close');
this.socketPort.destroy();
}
});
}

this.emit('close');
}

public readParameterRequest(parameterId: number) : Promise<Command> {
Expand Down
131 changes: 65 additions & 66 deletions src/adapter/ezsp/driver/uart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,35 +83,28 @@ export class SerialDriver extends EventEmitter {
this.parser = new Parser();
this.serialPort.pipe(this.parser);
this.parser.on('parsed', this.onParsed.bind(this));
try {
await new Promise((resolve, reject): void => {
this.serialPort.open(async (error): Promise<void> => {
if (error) {
reject(new Error(`Error while opening serialport '${error}'`));
} else {
resolve(null);
}
});
});

try {
await this.serialPort.asyncOpen();
debug('Serialport opened');

this.serialPort.once('close', this.onPortClose.bind(this));
this.serialPort.once('error', (error) => {
debug(`Serialport error: ${error}`);
});

this.serialPort.once('error', this.onPortError.bind(this));

// reset
await this.reset();

this.initialized = true;
this.emit('connected');
} catch (e) {
} catch (error) {
this.initialized = false;

if (this.serialPort.isOpen) {
this.serialPort.close();
}
throw e;

throw error;
}

}

private async openSocketPort(path: string): Promise<void> {
Expand Down Expand Up @@ -295,44 +288,46 @@ export class SerialDriver extends EventEmitter {
this.parser.reset();
this.queue.clear();
return this.queue.execute<void>(async (): Promise<void> => {
debug(`--> Write reset`);
const waiter = this.waitFor(-1, 10000).start();
this.writer.sendReset();
debug(`-?- waiting reset`);
return waiter.promise.catch(async (e) => {
try {
debug(`--> Write reset`);
const waiter = this.waitFor(-1, 10000);
this.writer.sendReset();
debug(`-?- waiting reset`);
await waiter.start().promise;
debug(`-+- waiting reset success`);
} catch (e) {
debug(`--> Error: ${e}`);
this.emit('reset');
throw new Error(`Reset error: ${e}`);
}).then(()=>{
debug(`-+- waiting reset success`);
});
}
});

}

public close(): Promise<void> {
return new Promise((resolve, reject): void => {
this.queue.clear();
if (this.initialized) {
if (this.portType === 'serial') {
this.serialPort.flush((): void => {
this.serialPort.close((error): void => {
this.initialized = false;
this.emit('close');
error == null ?
resolve() :
reject(new Error(`Error while closing serialport '${error}'`));
});
});
} else {
this.socketPort.destroy();
resolve();
public async close(): Promise<void> {
debug('closing');
this.queue.clear();

if (this.initialized) {
this.initialized = false;

if (this.portType === 'serial') {
try {
await this.serialPort.asyncFlushAndClose();
} catch (error) {
this.emit('close');

throw error;
}
} else {
this.emit('close');
resolve();
this.socketPort.destroy();
}
});
}

this.emit('close');
}

private onPortError(error: Error): void {
debug(`Port error: ${error}`);
}

private onPortClose(): void {
Expand All @@ -352,32 +347,36 @@ export class SerialDriver extends EventEmitter {
const ackSeq = this.recvSeq;

return this.queue.execute<void>(async (): Promise<void> => {
debug(`--> DATA (${seq},${ackSeq},0): ${data.toString('hex')}`);
const randData = this.randomize(data);
const waiter = this.waitFor(nextSeq).start();
this.writer.sendData(randData, seq, 0, ackSeq);
debug(`-?- waiting (${nextSeq})`);
return waiter.promise.catch(async (e) => {
debug(`--> Error: ${e}`);

try {
const waiter = this.waitFor(nextSeq);
debug(`--> DATA (${seq},${ackSeq},0): ${data.toString('hex')}`);
this.writer.sendData(randData, seq, 0, ackSeq);
debug(`-?- waiting (${nextSeq})`);
await waiter.start().promise;
debug(`-+- waiting (${nextSeq}) success`);
} catch (e1) {
debug(`--> Error: ${e1}`);
debug(`-!- break waiting (${nextSeq})`);
debug(`Can't send DATA frame (${seq},${ackSeq},0): ${data.toString('hex')}`);
await Wait(500);
debug(`->> DATA (${seq},${ackSeq},1): ${data.toString('hex')}`);
const waiter = this.waitFor(nextSeq).start();
this.writer.sendData(randData, seq, 1, ackSeq);
debug(`-?- rewaiting (${nextSeq})`);
return waiter.promise.catch(async (e) => {
debug(`--> Error: ${e}`);

try {
await Wait(500);
const waiter = this.waitFor(nextSeq);
debug(`->> DATA (${seq},${ackSeq},1): ${data.toString('hex')}`);
this.writer.sendData(randData, seq, 1, ackSeq);
debug(`-?- rewaiting (${nextSeq})`);
await waiter.start().promise;
debug(`-+- rewaiting (${nextSeq}) success`);
} catch (e2) {
debug(`--> Error: ${e2}`);
debug(`-!- break rewaiting (${nextSeq})`);
debug(`Can't resend DATA frame (${seq},${ackSeq},1): ${data.toString('hex')}`);
this.emit('reset');
throw new Error(`sendDATA error: ${e}`);
}).then(()=>{
debug(`-+- rewaiting (${nextSeq}) success`);
});
}).then(()=>{
debug(`-+- waiting (${nextSeq}) success`);
});
throw new Error(`sendDATA error: try 1: ${e1}, try 2: ${e2}`);
}
}
});
}

Expand Down
30 changes: 30 additions & 0 deletions src/adapter/serialPort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,34 @@ export class SerialPort<T extends AutoDetectTypes = AutoDetectTypes> extends Ser
};
super(opts, openCallback);
}

public async asyncOpen(): Promise<void> {
return new Promise((resolve, reject): void => {
this.open((error: Error | null): void => {
if (error) {
reject(new Error(`Error while opening serialport '${error}'`));
} else {
resolve();
}
});
});
}

public async asyncFlushAndClose(): Promise<void> {
return new Promise((resolve, reject): void => {
this.flush((flushError: Error | null): void => {
if (flushError) {
reject(new Error(`Error while flushing serialport '${flushError}'`));
} else {
this.close((closeError: Error | null): void => {
if (closeError) {
reject(new Error(`Error while closing serialport '${closeError}'`));
} else {
resolve();
}
});
}
});
})
}
}
Loading