Skip to content

Commit

Permalink
Skip bootloader on certain devices with rts/dtr connected. (Koenkk#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
Koenkk authored Jul 7, 2020
1 parent 6d40d54 commit eb92214
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/adapter/z-stack/adapter/zStackAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,16 @@ class ZStackAdapter extends Adapter {
public async start(): Promise<StartResult> {
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.
Expand Down
19 changes: 19 additions & 0 deletions src/adapter/z-stack/znp/znp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ class Znp extends events.EventEmitter {
}

private async skipBootloader(): Promise<void> {
// 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]);
Expand All @@ -210,6 +221,14 @@ class Znp extends events.EventEmitter {
await Wait(1000);
}

private async setSerialPortOptions(options: {dtr?: boolean; rts?: boolean}): Promise<void> {
return new Promise((resolve): void => {
this.serialPort.set(options, () => {
resolve();
});
});
}

public static async isValidPath(path: string): Promise<boolean> {
// For TCP paths we cannot get device information, therefore we cannot validate it.
if (SocketPortUtils.isTcpPath(path)) {
Expand Down
3 changes: 3 additions & 0 deletions test/adapter/z-stack/znp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -30,6 +31,7 @@ jest.mock('serialport', () => {
once: mockSerialPortOnce,
open: mockSerialPortOpen,
pipe: mockSerialPortPipe,
set: mockSerialPortSet,
write: mockSerialPortWrite,
flush: mockSerialPortFlush,
isOpen: mockSerialPortIsOpen,
Expand Down Expand Up @@ -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);
});

Expand Down

0 comments on commit eb92214

Please sign in to comment.