Skip to content

Commit

Permalink
fix: Improve EZSP connect logic (#869)
Browse files Browse the repository at this point in the history
* Improve EZSP connect logic.

* CI fix.

* Lint fix
  • Loading branch information
Nerivec authored Jan 13, 2024
1 parent 41a4543 commit a02a8e1
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 41 deletions.
22 changes: 13 additions & 9 deletions src/adapter/ezsp/adapter/ezspAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ class EZSPAdapter extends Adapter {
debug(`Adapter concurrent: ${concurrent}`);
this.queue = new Queue(concurrent);

this.driver = new Driver();
this.driver = new Driver(this.port.path, {
baudRate: this.port.baudRate || 115200,
rtscts: this.port.rtscts,
parity: 'none',
stopBits: 1,
xon: true,
xoff: true
}, this.networkOptions, this.greenPowerGroup);
this.driver.on('deviceJoined', this.handleDeviceJoin.bind(this));
this.driver.on('deviceLeft', this.handleDeviceLeft.bind(this));
this.driver.on('incomingMessage', this.processMessage.bind(this));
Expand Down Expand Up @@ -169,14 +176,11 @@ class EZSPAdapter extends Adapter {
* Adapter methods
*/
public async start(): Promise<StartResult> {
return await this.driver.startup(this.port.path, {
baudRate: this.port.baudRate || 115200,
rtscts: this.port.rtscts,
parity: 'none',
stopBits: 1,
xon: true,
xoff: true
}, this.networkOptions, this.greenPowerGroup);
try {
return await this.driver.startup();
} catch {
return await this.driver.reset();
}
}

public async stop(): Promise<void> {
Expand Down
54 changes: 30 additions & 24 deletions src/adapter/ezsp/driver/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,30 @@ export class Driver extends EventEmitter {
/* eslint-disable-next-line @typescript-eslint/no-explicit-any*/
private serialOpt: Record<string, any>;

constructor() {
/* eslint-disable-next-line @typescript-eslint/no-explicit-any*/
constructor(port: string, serialOpt: Record<string, any>, nwkOpt: TsType.NetworkOptions, greenPowerGroup: number) {
super();


this.nwkOpt = nwkOpt;
this.port = port;
this.serialOpt = serialOpt;
this.greenPowerGroup = greenPowerGroup;
this.waitress = new Waitress<EmberFrame, EmberWaitressMatcher>(
this.waitressValidator, this.waitressTimeoutFormatter);
}
private async onReset(): Promise<void> {

public async reset(): Promise<TsType.StartResult> {
let attempts = 0;
const pauses = [10, 30, 60];
let pause = 0;

// infinite retries
while (true) {
debug.log(`Reset connection. Try ${attempts}`);
try {
await this.stop();
await Wait(1000);
await this.startup(this.port, this.serialOpt, this.nwkOpt, this.greenPowerGroup);
break;
return await this.startup();
} catch (e) {
debug.error(`Reset error ${e.stack}`);
attempts += 1;
Expand All @@ -122,37 +128,37 @@ export class Driver extends EventEmitter {
}
}

/* eslint-disable-next-line @typescript-eslint/no-explicit-any*/
public async startup(port: string, serialOpt: Record<string, any>, nwkOpt: TsType.NetworkOptions,
greenPowerGroup: number): Promise<TsType.StartResult> {
private async onReset(): Promise<void> {
await this.reset();
}

public async startup(): Promise<TsType.StartResult> {
let result: TsType.StartResult = 'resumed';
this.nwkOpt = nwkOpt;
this.port = port;
this.serialOpt = serialOpt;
this.greenPowerGroup = greenPowerGroup;
this.transactionID = 1;
this.ezsp = undefined;
this.ezsp = new Ezsp();
this.ezsp.on('reset', this.onReset.bind(this));
this.ezsp.on('close', this.onClose.bind(this));

await this.ezsp.connect(port, serialOpt);
await this.ezsp.version();

await this.ezsp.updateConfig();
try {
await this.ezsp.connect(this.port, this.serialOpt);
} catch (error) {
debug.error(`EZSP could not connect: ${error.cause ?? error}`);

throw error;
}

await this.ezsp.updatePolicies();
this.ezsp.on('reset', this.onReset.bind(this));

await this.ezsp.version();
await this.ezsp.updateConfig();
await this.ezsp.updatePolicies();
//await this.ezsp.setValue(EzspValueId.VALUE_MAXIMUM_OUTGOING_TRANSFER_SIZE, 82);
//await this.ezsp.setValue(EzspValueId.VALUE_MAXIMUM_INCOMING_TRANSFER_SIZE, 82);
await this.ezsp.setValue(EzspValueId.VALUE_END_DEVICE_KEEP_ALIVE_SUPPORT_MODE, 3);
await this.ezsp.setValue(EzspValueId.VALUE_CCA_THRESHOLD, 0);

await this.ezsp.setSourceRouting();

//const count = await ezsp.getConfigurationValue(EzspConfigId.CONFIG_APS_UNICAST_MESSAGE_COUNT);
//debug.log("APS_UNICAST_MESSAGE_COUNT is set to %s", count);

await this.addEndpoint({
inputClusters: [0x0000, 0x0003, 0x0006, 0x000A, 0x0019, 0x001A, 0x0300],
outputClusters: [0x0000, 0x0003, 0x0004, 0x0005, 0x0006, 0x0008, 0x0020,
Expand Down Expand Up @@ -187,7 +193,7 @@ export class Driver extends EventEmitter {
revision: vers
};

if (await this.needsToBeInitialised(nwkOpt)) {
if (await this.needsToBeInitialised(this.nwkOpt)) {
const res = await this.ezsp.execCommand('networkState');
debug.log(`Network state ${res.status}`);
if (res.status == EmberNetworkStatus.JOINED_NETWORK) {
Expand Down Expand Up @@ -223,7 +229,7 @@ export class Driver extends EventEmitter {

this.multicast = new Multicast(this);
await this.multicast.startup([]);
await this.multicast.subscribe(greenPowerGroup, 242);
await this.multicast.subscribe(this.greenPowerGroup, 242);
// await this.multicast.subscribe(1, 901);
return result;
}
Expand Down
25 changes: 19 additions & 6 deletions src/adapter/ezsp/driver/ezsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const debug = {
};


const MAX_SERIAL_CONNECT_ATTEMPTS = 4;
const MTOR_MIN_INTERVAL = 10;
const MTOR_MAX_INTERVAL = 90;
const MTOR_ROUTE_ERROR_THRESHOLD = 4;
Expand Down Expand Up @@ -259,25 +260,33 @@ export class Ezsp extends EventEmitter {
this.serialDriver = new SerialDriver();
this.serialDriver.on('received', this.onFrameReceived.bind(this));
this.serialDriver.on('close', this.onClose.bind(this));
this.serialDriver.on('reset', this.resetHandler.bind(this));
}

public async connect(path: string, options: Record<string, number|boolean>): Promise<void> {
let lastError = null;
for (let i = 1; i < 5; i += 1) {

for (let i = 1; i <= MAX_SERIAL_CONNECT_ATTEMPTS; i++) {
try {
await this.serialDriver.connect(path, options);
break;
} catch (error) {
debug.error(`Connection attempt ${i} error: ${error.stack}`);
await Wait(5000);
debug.log(`Next attempt ${i+1}`);

if (i < MAX_SERIAL_CONNECT_ATTEMPTS) {
await Wait(5000);
debug.log(`Next attempt ${i+1}`);
}

lastError = error;
}
}

if (!this.serialDriver.isInitialized()) {
throw new Error("Failure to connect", {cause: lastError});
}

this.serialDriver.on('reset', this.onReset.bind(this));

if (WATCHDOG_WAKE_PERIOD) {
this.watchdogTimer = setInterval(
this.watchdogHandler.bind(this),
Expand Down Expand Up @@ -665,12 +674,16 @@ export class Ezsp extends EventEmitter {
this.failures += 1;
if (this.failures > MAX_WATCHDOG_FAILURES) {
this.failures = 0;
this.resetHandler();
this.reset();
}
}
}

private async resetHandler(): Promise<void> {
private reset(): void {
this.emit('reset');
}

private onReset(): void {
this.reset();
}
}
2 changes: 1 addition & 1 deletion src/adapter/ezsp/driver/uart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class SerialDriver extends EventEmitter {
debug('Serialport opened');

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

// reset
await this.reset();
Expand Down
2 changes: 1 addition & 1 deletion test/adapter/ezsp/uart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('UART', () => {

expect(mockSerialPortPipe).toHaveBeenCalledTimes(1);
expect(mockSerialPortAsyncOpen).toHaveBeenCalledTimes(1);
expect(mockSerialPortOnce).toHaveBeenCalledTimes(2);
expect(mockSerialPortOnce).toHaveBeenCalledTimes(1);
expect(writeBufferSpy).toHaveBeenCalledTimes(1);
});

Expand Down

0 comments on commit a02a8e1

Please sign in to comment.