diff --git a/packages/terminal/lib/index.js b/packages/terminal/lib/index.js index 271aeb534..62c8b2743 100755 --- a/packages/terminal/lib/index.js +++ b/packages/terminal/lib/index.js @@ -1,71 +1,54 @@ -#!/usr/bin/env node - +// #!/usr/bin/env node +const { Select } = require('enquirer') +const args = require('commander') const SerialPort = require('serialport') const { version } = require('../package.json') -const args = require('commander') -const PromptList = require('prompt-list') +const { OutputTranslator } = require('./output-translator') -function makeNumber(input) { - return Number(input) -} +const makeNumber = input => Number(input) args .version(version) .usage('[options]') .description('A basic terminal interface for communicating over a serial port. Pressing ctrl+c exits.') .option('-l --list', 'List available ports then exit') - .option('-p, --port ', 'Path or Name of serial port') + .option('-p, --path ', 'Path of the serial port') .option('-b, --baud ', 'Baud rate default: 9600', makeNumber, 9600) .option('--databits ', 'Data bits default: 8', makeNumber, 8) .option('--parity ', 'Parity default: none', 'none') .option('--stopbits ', 'Stop bits default: 1', makeNumber, 1) - // TODO make this on by default - .option('--echo --localecho', 'Print characters as you type them.') + .option('--no-echo', "Don't print characters as you type them.") .parse(process.argv) -function logErrorAndExit(error) { - console.error(error) - process.exit(1) -} - -function listPorts() { - SerialPort.list().then( - ports => { - ports.forEach(port => { - console.log(`${port.path}\t${port.pnpId || ''}\t${port.manufacturer || ''}`) - }) - }, - err => { - console.error('Error listing ports', err) - } - ) +const listPorts = async () => { + const ports = await SerialPort.list() + for (port of ports) { + console.log(`${port.path}\t${port.pnpId || ''}\t${port.manufacturer || ''}`) + } } -function askForPort() { - return SerialPort.list().then(ports => { - if (ports.length === 0) { - console.error('No ports detected and none specified') - process.exit(2) - } - - const portSelection = new PromptList({ - name: 'serial-port-selection', - message: 'Select a serial port to open', - choices: ports.map((port, i) => ({ - value: `[${i + 1}]\t${port.path}\t${port.pnpId || ''}\t${port.manufacturer || ''}`, - name: port.path, - })), - validate: Boolean, // ensure we picked something - }) +const askForPort = async () => { + const ports = await SerialPort.list() + if (ports.length === 0) { + console.error('No ports detected and none specified') + process.exit(2) + } - return portSelection.run().then(answer => { - console.log(`Opening serial port: ${answer}`) - return answer - }) - }) + const answer = await new Select({ + name: 'serial-port-selection', + message: 'Select a serial port to open', + choices: ports.map((port, i) => ({ + value: `[${i + 1}]\t${port.path}\t${port.pnpId || ''}\t${port.manufacturer || ''}`, + name: port.path, + })), + required: true, + }).run() + return answer } -function createPort(selectedPort) { +const createPort = path => { + console.log(`Opening serial port: ${path} echo: ${args.echo}`) + const openOptions = { baudRate: args.baud, dataBits: args.databits, @@ -73,31 +56,13 @@ function createPort(selectedPort) { stopBits: args.stopbits, } - const port = new SerialPort(selectedPort, openOptions) - - process.stdin.resume() - process.stdin.setRawMode(true) - process.stdin.on('data', s => { - if (s[0] === 0x03) { - port.close() - process.exit(0) - } - if (args.localecho) { - if (s[0] === 0x0d) { - process.stdout.write('\n') - } else { - process.stdout.write(s) - } - } - port.write(s) - }) - - port.on('data', data => { - process.stdout.write(data.toString()) - }) + const port = new SerialPort(path, openOptions) + const output = new OutputTranslator() + output.pipe(process.stdout) + port.pipe(output) port.on('error', err => { - console.log('Error', err) + console.error('Error', err) process.exit(1) }) @@ -105,12 +70,38 @@ function createPort(selectedPort) { console.log('Closed', err) process.exit(err ? 1 : 0) }) + process.stdin.setRawMode(true) + process.stdin.on('data', input => { + for (const byte of input) { + // ctrl+c + if (byte === 0x03) { + port.close() + process.exit(0) + } + } + port.write(input) + if (args.echo) { + output.write(input) + } + }) + process.stdin.resume() + + process.stdin.on('end', () => { + port.close() + process.exit(0) + }) } -if (args.list) { - listPorts() -} else { - Promise.resolve(args.port || askForPort()) - .then(createPort) - .catch(logErrorAndExit) +const run = async () => { + if (args.list) { + listPorts() + return + } + const path = args.path || (await askForPort()) + await createPort(path) } + +run().catch(error => { + console.error(error) + process.exit(1) +}) diff --git a/packages/terminal/lib/output-translator.js b/packages/terminal/lib/output-translator.js new file mode 100644 index 000000000..0b1971e9a --- /dev/null +++ b/packages/terminal/lib/output-translator.js @@ -0,0 +1,18 @@ +const { Transform } = require('stream') + +/** + * Convert carriage returns to newlines for output + */ +class OutputTranslator extends Transform { + _transform(chunk, _encoding, cb) { + for (let index = 0; index < chunk.length; index++) { + const byte = chunk[index] + if (byte === 0x0d) { + chunk[index] = 0x0a + } + } + this.push(chunk) + cb() + } +} +module.exports.OutputTranslator = OutputTranslator diff --git a/packages/terminal/package.json b/packages/terminal/package.json index 26d9a5f3a..22d9342b0 100644 --- a/packages/terminal/package.json +++ b/packages/terminal/package.json @@ -6,8 +6,8 @@ "serialport-terminal": "./lib/index.js" }, "dependencies": { - "commander": "^2.13.0", - "prompt-list": "^3.2.0", + "commander": "^3.0.2", + "enquirer": "^2.3.2", "serialport": "^8.0.3" }, "engines": {