-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #63.
- Loading branch information
Showing
9 changed files
with
1,314 additions
and
386 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
"prestart": "npm run build", | ||
"start": "node cli.js", | ||
"dev": "tsc && webpack --mode=development -w & node cli.js", | ||
"deploy": "rimraf dist/ui && IS_WEB=1 webpack --mode=production && gh-pages -d dist/ui", | ||
"test": "jest" | ||
}, | ||
"author": "Jeremy Apthorp <[email protected]>", | ||
|
@@ -39,6 +40,7 @@ | |
"@types/react": "^16.7.20", | ||
"@types/react-dom": "^16.0.11", | ||
"@types/serialport": "^8.0.0", | ||
"@types/w3c-web-serial": "^1.0.2", | ||
"@types/ws": "^6.0.1", | ||
"@types/yargs": "^12.0.8", | ||
"@typescript-eslint/eslint-plugin": "^1.5.0", | ||
|
@@ -49,6 +51,7 @@ | |
"eslint": "^5.15.3", | ||
"eslint-plugin-react": "^7.12.4", | ||
"file-loader": "^3.0.1", | ||
"gh-pages": "^3.2.3", | ||
"html-webpack-plugin": "^3.2.0", | ||
"jest": "^26.6.3", | ||
"react": "^16.8.0-alpha.1", | ||
|
@@ -68,9 +71,10 @@ | |
"express": "^4.16.4", | ||
"flatten-svg": "^0.2.1", | ||
"optimize-paths": "^1.2.0", | ||
"serialport": "^8.0.7", | ||
"serialport": "^9.2.0", | ||
"svgdom": "0.0.21", | ||
"wake-lock": "^0.2.0", | ||
"web-streams-polyfill": "^3.0.3", | ||
"ws": "^7.4.6", | ||
"yargs": "^15.4.1" | ||
}, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
export class RegexParser extends TransformStream { | ||
public constructor(opts: { regex: RegExp }) { | ||
if (opts.regex === undefined) { | ||
throw new TypeError('"options.regex" must be a regular expression pattern or object') | ||
} | ||
|
||
if (!(opts.regex instanceof RegExp)) { | ||
opts.regex = new RegExp(opts.regex) | ||
} | ||
|
||
const regex = opts.regex | ||
let data = '' | ||
const decoder = new TextDecoder() | ||
super({ | ||
transform(chunk, controller) { | ||
const newData = data + decoder.decode(chunk) | ||
const parts = newData.split(regex) | ||
data = parts.pop() | ||
parts.forEach(part => { | ||
controller.enqueue(part) | ||
}) | ||
}, | ||
flush(controller) { | ||
controller.enqueue(data) | ||
data = '' | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { EventEmitter } from "events"; | ||
import { default as NodeSerialPort } from "serialport"; | ||
|
||
function readableStreamFromAsyncIterable<T>(iterable: AsyncIterable<T>) { | ||
const it = iterable[Symbol.asyncIterator](); | ||
return new ReadableStream({ | ||
async pull(controller) { | ||
const { done, value } = await it.next(); | ||
if (done) { | ||
controller.close(); | ||
} else { | ||
controller.enqueue(value); | ||
} | ||
}, | ||
async cancel(reason) { | ||
await it.throw(reason); | ||
} | ||
}, { highWaterMark: 0 }); | ||
} | ||
|
||
export class SerialPortSerialPort extends EventEmitter implements SerialPort { | ||
private _path: string; | ||
private _port: NodeSerialPort | ||
|
||
public constructor(path: string) { | ||
super() | ||
this._path = path | ||
} | ||
|
||
public onconnect: (this: this, ev: Event) => any; | ||
public ondisconnect: (this: this, ev: Event) => any; | ||
public readable: ReadableStream<Uint8Array>; | ||
public writable: WritableStream<Uint8Array>; | ||
|
||
public open(options: SerialOptions): Promise<void> { | ||
const opts: NodeSerialPort.OpenOptions = { | ||
baudRate: options.baudRate, | ||
} | ||
if (options.dataBits != null) | ||
opts.dataBits = options.dataBits as any | ||
if (options.stopBits != null) | ||
opts.stopBits = options.stopBits as any | ||
if (options.parity != null) | ||
opts.parity = options.parity | ||
|
||
/* | ||
TODO: | ||
bufferSize?: number | undefined; | ||
flowControl?: FlowControlType | undefined; | ||
*/ | ||
return new Promise((resolve, reject) => { | ||
this._port = new NodeSerialPort(this._path, opts, (err) => { | ||
this._port.once('close', () => this.emit('disconnect')) | ||
if (err) reject(err) | ||
else { | ||
// Drain the port | ||
while (this._port.read() != null) { /* do nothing */ } | ||
resolve() | ||
} | ||
}) | ||
this.readable = readableStreamFromAsyncIterable(this._port) | ||
this.writable = new WritableStream({ | ||
write: (chunk) => { | ||
return new Promise((resolve, reject) => { | ||
this._port.write(Buffer.from(chunk), (err, _bytesWritten) => { | ||
if (err) reject(err) | ||
else resolve() | ||
// TODO: check bytesWritten? | ||
}) | ||
}) | ||
} | ||
}) | ||
}) | ||
} | ||
public setSignals(signals: SerialOutputSignals): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
this._port.set({ | ||
dtr: signals.dataTerminalReady, | ||
rts: signals.requestToSend, | ||
brk: signals.break | ||
}, (err) => { | ||
if (err) reject(err) | ||
else resolve() | ||
}) | ||
}) | ||
} | ||
public getSignals(): Promise<SerialInputSignals> { | ||
throw new Error("Method not implemented."); | ||
} | ||
public getInfo(): SerialPortInfo { | ||
throw new Error("Method not implemented."); | ||
} | ||
public close(): Promise<void> { | ||
return new Promise((resolve, reject) => { | ||
this._port.close((err) => { | ||
if (err) reject(err) | ||
else resolve() | ||
}) | ||
}) | ||
} | ||
|
||
public addEventListener(type: "connect" | "disconnect", listener: (this: this, ev: Event) => any, useCapture?: boolean): void; | ||
public addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; | ||
public addEventListener(type: any, listener: any, options?: any): void { | ||
if (typeof options === 'object' && options.once) { | ||
this.once(type, listener) | ||
} else { | ||
this.on(type, listener) | ||
} | ||
} | ||
|
||
public removeEventListener(type: "connect" | "disconnect", callback: (this: this, ev: Event) => any, useCapture?: boolean): void; | ||
public removeEventListener(type: string, callback: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; | ||
public removeEventListener(type: any, callback: any, options?: any): void { | ||
if (typeof options === 'object' && options.once) { | ||
this.off(type, callback) | ||
} else { | ||
this.off(type, callback) | ||
} | ||
} | ||
|
||
public dispatchEvent(event: Event): boolean { | ||
return this.emit(event.type) | ||
} | ||
} |
Oops, something went wrong.