From eb922140a7e2378d0724314ae2a1b65ae62fa4fd Mon Sep 17 00:00:00 2001 From: Koen Kanters Date: Tue, 7 Jul 2020 21:02:25 +0200 Subject: [PATCH] Skip bootloader on certain devices with rts/dtr connected. (#196) --- src/adapter/z-stack/adapter/zStackAdapter.ts | 14 ++++++++++---- src/adapter/z-stack/znp/znp.ts | 19 +++++++++++++++++++ test/adapter/z-stack/znp.test.ts | 3 +++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/adapter/z-stack/adapter/zStackAdapter.ts b/src/adapter/z-stack/adapter/zStackAdapter.ts index 6359f0888f9067..29e9863d45e9e7 100644 --- a/src/adapter/z-stack/adapter/zStackAdapter.ts +++ b/src/adapter/z-stack/adapter/zStackAdapter.ts @@ -79,10 +79,16 @@ class ZStackAdapter extends Adapter { public async start(): Promise { await this.znp.open(); - try { - await this.znp.request(Subsystem.SYS, 'ping', {capabilities: 1}); - } catch (e) { - throw new Error(`Failed to connect to the adapter (${e})`); + const attempts = 3; + for (let i = 0; i < attempts; i++) { + try { + await this.znp.request(Subsystem.SYS, 'ping', {capabilities: 1}); + break; + } catch (e) { + if (attempts - 1 === i) { + throw new Error(`Failed to connect to the adapter (${e})`); + } + } } // Old firmware did not support version, assume it's Z-Stack 1.2 for now. diff --git a/src/adapter/z-stack/znp/znp.ts b/src/adapter/z-stack/znp/znp.ts index f257fc129aceb6..6d8c16a00798e2 100755 --- a/src/adapter/z-stack/znp/znp.ts +++ b/src/adapter/z-stack/znp/znp.ts @@ -202,6 +202,17 @@ class Znp extends events.EventEmitter { } private async skipBootloader(): Promise { + // Skip bootloader on some CC2652 devices (e.g. zzh-p) + if (this.serialPort) { + await this.setSerialPortOptions({dtr: false, rts: false}); + await Wait(150); + await this.setSerialPortOptions({dtr: false, rts: true}); + await Wait(150); + await this.setSerialPortOptions({dtr: false, rts: false}); + await Wait(150); + } + + // Skip bootloader on CC2530/CC2531 // Send magic byte: https://github.com/Koenkk/zigbee2mqtt/issues/1343 to bootloader // and give ZNP 1 second to start. const buffer = Buffer.from([0xef]); @@ -210,6 +221,14 @@ class Znp extends events.EventEmitter { await Wait(1000); } + private async setSerialPortOptions(options: {dtr?: boolean; rts?: boolean}): Promise { + return new Promise((resolve): void => { + this.serialPort.set(options, () => { + resolve(); + }); + }); + } + public static async isValidPath(path: string): Promise { // For TCP paths we cannot get device information, therefore we cannot validate it. if (SocketPortUtils.isTcpPath(path)) { diff --git a/test/adapter/z-stack/znp.test.ts b/test/adapter/z-stack/znp.test.ts index 13103bf3442592..9588108dd74afc 100644 --- a/test/adapter/z-stack/znp.test.ts +++ b/test/adapter/z-stack/znp.test.ts @@ -13,6 +13,7 @@ const mockSerialPortList = jest.fn().mockReturnValue([]); const mockSerialPortOpen = jest.fn().mockImplementation((cb) => cb()); const mockSerialPortConstructor = jest.fn(); const mockSerialPortOnce = jest.fn(); +const mockSerialPortSet = jest.fn().mockImplementation((opts, cb) => cb()); const mockSerialPortWrite = jest.fn((buffer, cb) => cb()); let mockSerialPortIsOpen = false; @@ -30,6 +31,7 @@ jest.mock('serialport', () => { once: mockSerialPortOnce, open: mockSerialPortOpen, pipe: mockSerialPortPipe, + set: mockSerialPortSet, write: mockSerialPortWrite, flush: mockSerialPortFlush, isOpen: mockSerialPortIsOpen, @@ -134,6 +136,7 @@ describe('ZNP', () => { expect(mockSerialPortPipe).toHaveBeenCalledTimes(1); expect(mockSerialPortOpen).toHaveBeenCalledTimes(1); expect(mockUnpiWriterWriteBuffer).toHaveBeenCalledTimes(1); + expect(mockSerialPortSet).toHaveBeenCalledTimes(3); expect(mockSerialPortOnce).toHaveBeenCalledTimes(2); });