108 lines
2.8 KiB
TypeScript
108 lines
2.8 KiB
TypeScript
import { ReadableWebToNodeStream } from 'readable-web-to-node-stream'
|
|
export type Port = {
|
|
readable: ReadableStream
|
|
writable: WritableStream
|
|
open: (options: SerialOptions) => Promise<void>
|
|
close: () => Promise<void>
|
|
getInfo: () => { usbProductId: number; usbVendorId: number }
|
|
}
|
|
export type PortFilters = { filters?: { usbVendorId: number; usbProductId: number }[] }
|
|
export type NavigatorSerial = {
|
|
requestPort: (optns: PortFilters) => Port
|
|
getPorts: () => Promise<Port[]>
|
|
}
|
|
export type SerialOptions = {
|
|
baudRate?: number
|
|
dataBits?: number
|
|
stopBits?: number
|
|
parity?: string
|
|
bufferSize?: number
|
|
rtscts?: boolean
|
|
xon?: boolean
|
|
xoff?: boolean
|
|
xany?: boolean
|
|
}
|
|
declare global {
|
|
interface Window {
|
|
serial: Serial
|
|
}
|
|
interface Navigator {
|
|
serial: NavigatorSerial
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface Window {
|
|
serial2: Serial
|
|
}
|
|
interface Navigator {
|
|
serial: NavigatorSerial
|
|
}
|
|
}
|
|
|
|
export class Serial {
|
|
port?: Port
|
|
reader?: NodeJS.ReadableStream
|
|
writer?: WritableStreamDefaultWriter
|
|
|
|
async close() {
|
|
if (this.reader) {
|
|
const reader = this.reader
|
|
this.reader = undefined
|
|
// @ts-ignore
|
|
// this is specific to the "readable-web-to-node-stream" library
|
|
await reader.reader.cancel()
|
|
// await this.reader.close() // this blocks if uploading failed
|
|
}
|
|
if (this.writer) {
|
|
const writer = this.writer
|
|
this.writer = undefined
|
|
await writer.close()
|
|
}
|
|
if (this.port) {
|
|
const port = this.port
|
|
this.port = undefined
|
|
await port.close()
|
|
}
|
|
}
|
|
async connectWithPaired(options: SerialOptions) {
|
|
const [port] = await navigator.serial.getPorts()
|
|
if (!port) throw new Error('no paired')
|
|
return this._connect(options, port)
|
|
}
|
|
async connect(options: SerialOptions, portFilters: PortFilters = {}) {
|
|
const port = await navigator.serial.requestPort(portFilters)
|
|
return this._connect(options, port)
|
|
}
|
|
async _connect(options: SerialOptions, port: Port) {
|
|
options = {
|
|
baudRate: 9600,
|
|
dataBits: 8,
|
|
stopBits: 1,
|
|
parity: 'none',
|
|
bufferSize: 255,
|
|
rtscts: false,
|
|
xon: false,
|
|
xoff: false,
|
|
...options,
|
|
}
|
|
if (this.port) await this.close()
|
|
this.port = port
|
|
await this.port.open(options)
|
|
this.reader = new ReadableWebToNodeStream(this.port.readable)
|
|
this.writer = this.port.writable.getWriter()
|
|
|
|
// next I'm faking a NodeJS.ReadWriteStream
|
|
const rwStream = (this.reader as unknown) as NodeJS.ReadWriteStream
|
|
// @ts-ignore
|
|
rwStream.write = (buffer: string | Uint8Array, onDone: (err: Error | null | undefined) => void) => {
|
|
this.writer!.write(buffer).then(() => onDone(null), onDone)
|
|
return true
|
|
}
|
|
return rwStream
|
|
}
|
|
}
|
|
const serial = new Serial()
|
|
|
|
export default serial
|