From 918a6be451d2b5081f0b9fec2a54555e50645f1e Mon Sep 17 00:00:00 2001 From: Nerivec <62446222+Nerivec@users.noreply.github.com> Date: Mon, 3 Jun 2024 22:36:07 +0200 Subject: [PATCH] 1.0.5 --- README.md | 14 +++---- package-lock.json | 12 +++--- package.json | 4 +- src/commands/bootloader/index.ts | 10 +---- src/commands/stack/index.ts | 7 ++-- src/utils/port.ts | 65 ++++++++++++++++++++++++++++---- src/utils/xmodem.ts | 2 +- 7 files changed, 75 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index b286e2a..ae13d3a 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ $ npm install -g ember-zli $ ember-zli COMMAND running command... $ ember-zli (--version) -ember-zli/1.0.4 win32-x64 node-v20.10.0 +ember-zli/1.0.5 win32-x64 node-v20.10.0 $ ember-zli --help [COMMAND] USAGE $ ember-zli COMMAND @@ -71,10 +71,9 @@ Interact with the Gecko bootloader in the adapter via serial. ``` USAGE - $ ember-zli bootloader [-a] [-f ] [-r] + $ ember-zli bootloader [-f ] [-r] FLAGS - -a, --ask Ask conf questions, even if conf file present (override file with new answers). -f, --file= Path to a firmware file. If not provided, will be set via interactive prompt when entering relevant menu. -r, --forceReset Try to force reset into bootloader. @@ -86,7 +85,7 @@ EXAMPLES $ ember-zli bootloader ``` -_See code: [src/commands/bootloader/index.ts](https://github.com/Nerivec/ember-zli/blob/v1.0.4/src/commands/bootloader/index.ts)_ +_See code: [src/commands/bootloader/index.ts](https://github.com/Nerivec/ember-zli/blob/v1.0.5/src/commands/bootloader/index.ts)_ ## `ember-zli help [COMMAND]` @@ -114,10 +113,7 @@ Interact with the EmberZNet stack in the adapter. ``` USAGE - $ ember-zli stack [-a] - -FLAGS - -a, --ask Ask conf questions, even if conf file present (override file with new answers). + $ ember-zli stack DESCRIPTION Interact with the EmberZNet stack in the adapter. @@ -126,7 +122,7 @@ EXAMPLES $ ember-zli stack ``` -_See code: [src/commands/stack/index.ts](https://github.com/Nerivec/ember-zli/blob/v1.0.4/src/commands/stack/index.ts)_ +_See code: [src/commands/stack/index.ts](https://github.com/Nerivec/ember-zli/blob/v1.0.5/src/commands/stack/index.ts)_ ## `ember-zli version` diff --git a/package-lock.json b/package-lock.json index 233d862..984f870 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ember-zli", - "version": "1.0.4", + "version": "1.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ember-zli", - "version": "1.0.4", + "version": "1.0.5", "license": "GPL-3.0-or-later", "dependencies": { "@inquirer/prompts": "^5.0.2", @@ -18,7 +18,7 @@ "cli-progress": "^3.12.0", "crc-32": "^1.2.2", "winston": "^3.13.0", - "zigbee-herdsman": "0.49.1" + "zigbee-herdsman": "0.49.2" }, "bin": { "ember-zli": "bin/run.js" @@ -8991,9 +8991,9 @@ } }, "node_modules/zigbee-herdsman": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.49.1.tgz", - "integrity": "sha512-TYTJO8kNUOL3WECk9KA3Il2cMTOFWTfXShYe5peq2LA4RA4JxDPyU/3y8teyz30vWK8bSkt0C8vMlKrYGV6IxQ==", + "version": "0.49.2", + "resolved": "https://registry.npmjs.org/zigbee-herdsman/-/zigbee-herdsman-0.49.2.tgz", + "integrity": "sha512-v+uWaCvFeVqXeXBH7+CRphPbn1gGEFkAK71uw9wqumW6S9bNZJQXZkgofo2rPmiv5oAkGaqQz2gCZQoWJn9QoA==", "license": "MIT", "dependencies": { "@serialport/bindings-cpp": "^12.0.1", diff --git a/package.json b/package.json index ac1db7b..1955597 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ember-zli", "description": "Interact with EmberZNet-based adapters using zigbee-herdsman 'ember' driver", - "version": "1.0.4", + "version": "1.0.5", "author": "Nerivec", "bin": { "ember-zli": "bin/run.js" @@ -17,7 +17,7 @@ "cli-progress": "^3.12.0", "crc-32": "^1.2.2", "winston": "^3.13.0", - "zigbee-herdsman": "0.49.1" + "zigbee-herdsman": "0.49.2" }, "devDependencies": { "@oclif/prettier-config": "^0.2.1", diff --git a/src/commands/bootloader/index.ts b/src/commands/bootloader/index.ts index 97a6279..3618936 100644 --- a/src/commands/bootloader/index.ts +++ b/src/commands/bootloader/index.ts @@ -6,7 +6,6 @@ import { join } from 'node:path' import { DATA_FOLDER, logger } from '../../index.js' import { BootloaderEvent, BootloaderMenu, GeckoBootloader } from '../../utils/bootloader.js' -import { TCP_REGEX } from '../../utils/consts.js' import { FirmwareSource, FirmwareValidation } from '../../utils/enums.js' import { getPortConf } from '../../utils/port.js' import { AdapterModel, FirmwareMetadata, FirmwareVersion } from '../../utils/types.js' @@ -121,20 +120,13 @@ export default class Bootloader extends Command { ] static override flags = { - ask: Flags.boolean({ char: 'a', description: 'Ask conf questions, even if conf file present (override file with new answers).' }), file: Flags.file({ char: 'f', description: 'Path to a firmware file. If not provided, will be set via interactive prompt when entering relevant menu.', exists: true }), forceReset: Flags.boolean({ char: 'r', default: false, description: 'Try to force reset into bootloader.' }), } public async run(): Promise { const {flags} = await this.parse(Bootloader) - const portConf = await getPortConf(!flags.ask) - - if (TCP_REGEX.test(portConf.path)) { - logger.error(`Interacting with bootloader over TCP is not supported.`) - return this.exit(1) - } - + const portConf = await getPortConf(true/* no TCP */) logger.debug(`Using port conf: ${JSON.stringify(portConf)}`) const adapterModelChoices: { name: string, value: AdapterModel | undefined }[] = [{ name: 'Not in this list', value: undefined }] diff --git a/src/commands/stack/index.ts b/src/commands/stack/index.ts index 6b47e41..a5e96da 100644 --- a/src/commands/stack/index.ts +++ b/src/commands/stack/index.ts @@ -1,5 +1,5 @@ import { checkbox, confirm, input, select } from '@inquirer/prompts' -import { Command, Flags } from '@oclif/core' +import { Command } from '@oclif/core' import { Presets, SingleBar } from 'cli-progress' import { existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs' import { dirname, extname, join } from 'node:path' @@ -56,12 +56,11 @@ export default class Stack extends Command { ] static override flags = { - ask: Flags.boolean({ char: 'a', description: 'Ask conf questions, even if conf file present (override file with new answers).' }), } public async run(): Promise { - const {flags} = await this.parse(Stack) - const portConf = await getPortConf(!flags.ask) + // const {flags} = await this.parse(Stack) + const portConf = await getPortConf() logger.debug(`Using port conf: ${JSON.stringify(portConf)}`) let ezsp = await emberStart(this, portConf) diff --git a/src/utils/port.ts b/src/utils/port.ts index ac438d7..c156661 100644 --- a/src/utils/port.ts +++ b/src/utils/port.ts @@ -1,18 +1,67 @@ -import { input, select } from '@inquirer/prompts' -import { readFileSync, writeFileSync } from 'node:fs' +import { confirm, input, select } from '@inquirer/prompts' +import { existsSync, readFileSync, writeFileSync } from 'node:fs' import { SerialPort } from 'zigbee-herdsman/dist/adapter/serialPort.js' import { CONF_PORT_PATH, logger } from '../index.js' import { BAUDRATES, TCP_REGEX } from './consts.js' import { BaudRate, PortConf, PortType } from './types.js' -export const getPortConf = async(useFile: boolean = true): Promise => { - if (useFile) { - try { - const conf = readFileSync(CONF_PORT_PATH, 'utf8') +export const getPortConfFile = async (noTCP: boolean = false): Promise => { + if (!existsSync(CONF_PORT_PATH)) { + return undefined + } + + const file = readFileSync(CONF_PORT_PATH, 'utf8') + + const conf: PortConf = JSON.parse(file) + + if (!conf.baudRate || !BAUDRATES.includes(conf.baudRate)) { + logger.error(`Cached config does not include a valid baudrate value.`) + return undefined + } + + if (!conf.path) { + logger.error(`Cached config does not include a valid path value.`) + return undefined + } + + if (TCP_REGEX.test(conf.path)) { + if (noTCP) { + throw new Error(`Interacting with bootloader over TCP is not supported.`) + } + } else { + const portList = await SerialPort.list() + + if (portList.length === 0) { + throw new Error('No serial device found.') + } - return JSON.parse(conf) - } catch {} + if (!portList.some((p) => p.path === conf.path)) { + logger.error(`Cached config path does not match a currently connected serial device.`) + return undefined + } + } + + if (conf.rtscts !== true && conf.rtscts !== false) { + logger.error(`Cached config does not include a valid rtscts value.`) + return undefined + } + + return conf +} + +export const getPortConf = async (noTCP: boolean = false): Promise => { + const portConfFile = await getPortConfFile(noTCP) + + if (portConfFile !== undefined) { + const usePortConfFile = await confirm({ + default: true, + message: `Baudrate: ${portConfFile.baudRate}, Path: ${portConfFile.path}, RTS/CTS: ${portConfFile.rtscts}. Use this config?`, + }) + + if (usePortConfFile) { + return portConfFile + } } const baudrateChoices = [] diff --git a/src/utils/xmodem.ts b/src/utils/xmodem.ts index 33e86ee..8703cea 100644 --- a/src/utils/xmodem.ts +++ b/src/utils/xmodem.ts @@ -81,7 +81,7 @@ export class XModemCRC extends EventEmitter { if (this.waitForBlock !== this.blockNum) { logger.warning(`Received out of sequence data: ${recdData.toString('hex')} (blockNum=${this.blockNum}, expected=${this.waitForBlock}).`, NS) this.retries-- - + if (this.retries === 0) { logger.error(`Maximum retries ${MAX_RETRIES} reached. Giving up.`, NS) this.emit(XEvent.STOP, XExitStatus.FAIL)