@danchitnis/comport
Advanced tools
Comparing version 0.1.1 to 0.1.2
/** | ||
* This code is inspired by Googles Serial Api example | ||
* https://codelabs.developers.google.com/codelabs/web-serial/ | ||
* | ||
* | ||
* Danial Chitnis | ||
* Danial Chitnis 2020 | ||
*/ | ||
@@ -14,7 +15,16 @@ export class ComPort extends EventTarget { | ||
if (this.reader) { | ||
await this.reader.cancel().catch(e => console.log('Error: ', e.message)); | ||
this.port.close(); | ||
await this.reader.cancel(); | ||
await this.inputDone.catch((e) => { console.log(e); }); | ||
this.reader = null; | ||
this.inputDone = null; | ||
} | ||
if (this.outputStream) { | ||
await this.outputStream.getWriter().close(); | ||
await this.outputDone.catch((e) => { console.log(e); }); | ||
this.outputStream = null; | ||
this.outputDone = null; | ||
} | ||
await this.port.close(); | ||
this.log("\nport is now closed!\n"); | ||
} | ||
this.log("\nport is closed now!\n"); | ||
} | ||
@@ -32,4 +42,7 @@ async connectSerialApi(baudrate) { | ||
const decoder = new TextDecoderStream(); | ||
const inputDone = this.port.readable.pipeTo(decoder.writable); | ||
this.inputDone = this.port.readable.pipeTo(decoder.writable); | ||
const inputStream = decoder.readable; | ||
const encoder = new TextEncoderStream(); | ||
this.outputDone = encoder.readable.pipeTo(this.port.writable); | ||
this.outputStream = encoder.writable; | ||
this.reader = inputStream.getReader(); | ||
@@ -86,3 +99,13 @@ this.readLoop(); | ||
} | ||
async writeToStream(line) { | ||
// CODELAB: Write to output stream | ||
const writer = this.outputStream.getWriter(); | ||
//console.log('[SEND]', line); | ||
await writer.write(line + '\n'); | ||
writer.releaseLock(); | ||
} | ||
sendLine(line) { | ||
this.writeToStream(line); | ||
} | ||
} | ||
//# sourceMappingURL=ComPort.js.map |
{ | ||
"name": "@danchitnis/comport", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "An easy to use package for Serial Api", | ||
@@ -5,0 +5,0 @@ "main": "./dist/ComPort", |
@@ -9,9 +9,15 @@ # ComPort | ||
Although [WebUSB](https://wicg.github.io/webusb/) has been around for some years, it is mainly targeted at companies intending to developed web-based firmwares. A major downside of WebUSB is once a native driver is installed on the OS, the device will no longer be recognized by WebUSB. Unlike WebUSB, the [Serial Api](https://wicg.github.io/serial/) is intended for use as a traditional COM port (Serial port) which includes many microcontroller based devices and USB-to-Serial devices such as FTDI and Cypress chipsets. Additionally, you can still implement your own USB CDC protocol, and have the OS driver and Web driver co-exist. The Serial Api opens doors for new and exciting web-based front-ends for small and medium sized embedded projects. | ||
## Why ComPort | ||
ComPort makes it easy for embedded developers to quickly build a modern front-end for their applications. It removes the hassle of dealing with async/await functions. This package is not intended for high-performance and high data-rate applications, but for quick and simple development. If high-performance is required then a browser based app is probably the wrong choice. | ||
## Potential use cases | ||
all serial communication to and from embedded hardware via USB-to-Serial bridges like FTDI cables and Arduino boards. | ||
## How to enable Serial Api (Chrome 79) | ||
[Enable it here!](chrome://flags/#enable-experimental-web-platform-features) | ||
Enable it in: chrome://flags/#enable-experimental-web-platform-features | ||
@@ -25,2 +31,8 @@ ## Build instructions | ||
## installation | ||
```bash | ||
npm i @danchitnis/comport | ||
``` | ||
## Examples | ||
@@ -27,0 +39,0 @@ |
/** | ||
* This code is inspired by Googles Serial Api example | ||
* https://codelabs.developers.google.com/codelabs/web-serial/ | ||
* | ||
* | ||
* Danial Chitnis | ||
* Danial Chitnis 2020 | ||
*/ | ||
type RxEventType = "rx" | "rx-msg"; | ||
type RxEventType = "rx" | "rx-msg"; | ||
export class ComPort extends EventTarget { | ||
port: SerialPort; | ||
private reader: ReadableStreamDefaultReader; | ||
private strRX = ""; | ||
export class ComPort extends EventTarget { | ||
port: SerialPort; | ||
private reader: ReadableStreamDefaultReader; | ||
private outputStream: WritableStream<string>; | ||
private inputDone: Promise<void>; | ||
private outputDone: Promise<void>; | ||
private strRX = ""; | ||
constructor() { | ||
super(); | ||
} | ||
constructor() { | ||
super(); | ||
} | ||
async disconnect(): Promise<void> { | ||
if (this.port) { | ||
if (this.reader) { | ||
await this.reader.cancel().catch(e => console.log('Error: ', e.message)); | ||
this.port.close(); | ||
} | ||
} | ||
this.log("\nport is closed now!\n"); | ||
} | ||
async disconnect(): Promise<void> { | ||
if (this.port) { | ||
if (this.reader) { | ||
await this.reader.cancel(); | ||
await this.inputDone.catch((e) => {console.log(e);}); | ||
this.reader = null; | ||
this.inputDone = null; | ||
} | ||
if (this.outputStream) { | ||
await this.outputStream.getWriter().close(); | ||
await this.outputDone.catch((e) => {console.log(e);}); | ||
this.outputStream = null; | ||
this.outputDone = null; | ||
} | ||
await this.port.close(); | ||
this.log("\nport is now closed!\n"); | ||
} | ||
} | ||
private async connectSerialApi(baudrate: Baudrate): Promise<void> { | ||
// CODELAB: Add code to request & open port here. | ||
// - Request a port and open a connection. | ||
this.log("Requesting port"); | ||
this.port = await navigator.serial.requestPort(); | ||
private async connectSerialApi(baudrate: Baudrate): Promise<void> { | ||
// CODELAB: Add code to request & open port here. | ||
// - Request a port and open a connection. | ||
this.log("Requesting port"); | ||
this.port = await navigator.serial.requestPort(); | ||
// - Wait for the port to open. | ||
this.log("Openning port"); | ||
await this.port.open({ baudrate: baudrate }); | ||
// - Wait for the port to open. | ||
this.log("Openning port"); | ||
await this.port.open({ baudrate: baudrate }); | ||
this.log("Port is now open 🎉"); | ||
// CODELAB: Add code to read the stream here. | ||
const decoder = new TextDecoderStream(); | ||
const inputDone = this.port.readable.pipeTo(decoder.writable); | ||
const inputStream = decoder.readable; | ||
this.reader = inputStream.getReader(); | ||
this.readLoop(); | ||
} | ||
this.log("Port is now open 🎉"); | ||
// CODELAB: Add code to read the stream here. | ||
const decoder = new TextDecoderStream(); | ||
this.inputDone = this.port.readable.pipeTo(decoder.writable); | ||
const inputStream = decoder.readable; | ||
async connect(baudrate: Baudrate): Promise<void> { | ||
// CODELAB: Add connect code here. | ||
try { | ||
await this.connectSerialApi(baudrate); | ||
console.log("here2 🥗"); | ||
} catch (error) { | ||
this.log("Error 😢: " + error + "\n"); | ||
} | ||
} | ||
private async readLoop(): Promise<void> { | ||
// CODELAB: Add read loop here. | ||
while (true) { | ||
try { | ||
const { value, done } = await this.reader.read(); | ||
if (value) { | ||
this.procInput(value); | ||
} | ||
if (done) { | ||
console.log('[readLoop] DONE', done); | ||
this.reader.releaseLock(); | ||
break; | ||
} | ||
} catch (e) { | ||
console.log(e); | ||
} | ||
} | ||
} | ||
const encoder = new TextEncoderStream(); | ||
this.outputDone = encoder.readable.pipeTo(this.port.writable); | ||
this.outputStream = encoder.writable; | ||
this.reader = inputStream.getReader(); | ||
this.readLoop(); | ||
} | ||
private procInput(str: string): void { | ||
this.strRX = this.strRX + str; | ||
const linesRX = this.strRX.split("\n"); | ||
if (linesRX.length > 1) { | ||
for (let i=0; i<linesRX.length-1; i++) { | ||
const event = new CustomEvent('rx',{detail: linesRX[i]}); | ||
this.dispatchEvent(event); | ||
} | ||
// save the reminder of the input line | ||
this.strRX = linesRX[ linesRX.length-1 ]; | ||
} | ||
} | ||
async connect(baudrate: Baudrate): Promise<void> { | ||
// CODELAB: Add connect code here. | ||
try { | ||
await this.connectSerialApi(baudrate); | ||
console.log("here2 🥗"); | ||
} catch (error) { | ||
this.log("Error 😢: " + error + "\n"); | ||
} | ||
} | ||
private async readLoop(): Promise<void> { | ||
// CODELAB: Add read loop here. | ||
while (true) { | ||
try { | ||
const { value, done } = await this.reader.read(); | ||
if (value) { | ||
this.procInput(value); | ||
} | ||
if (done) { | ||
console.log('[readLoop] DONE', done); | ||
this.reader.releaseLock(); | ||
break; | ||
} | ||
} catch (e) { | ||
console.log(e); | ||
} | ||
} | ||
} | ||
private log(str: string): void { | ||
const event = new CustomEvent("rx-msg",{detail:str}); | ||
this.dispatchEvent(event); | ||
} | ||
private procInput(str: string): void { | ||
this.strRX = this.strRX + str; | ||
const linesRX = this.strRX.split("\n"); | ||
if (linesRX.length > 1) { | ||
for (let i=0; i<linesRX.length-1; i++) { | ||
const event = new CustomEvent('rx',{detail: linesRX[i]}); | ||
this.dispatchEvent(event); | ||
addEventListener(eventType: "rx" | "rx-msg", listener: (this: this, ev: CustomEvent<string>) => void): void { | ||
super.addEventListener(eventType, listener); | ||
} | ||
} | ||
// save the reminder of the input line | ||
this.strRX = linesRX[ linesRX.length-1 ]; | ||
} | ||
} | ||
} | ||
private log(str: string): void { | ||
const event = new CustomEvent("rx-msg",{detail:str}); | ||
this.dispatchEvent(event); | ||
} | ||
addEventListener(eventType: "rx" | "rx-msg", listener: (this: this, ev: CustomEvent<string>) => void): void { | ||
super.addEventListener(eventType, listener); | ||
} | ||
private async writeToStream(line: string): Promise<void> { | ||
// CODELAB: Write to output stream | ||
const writer = this.outputStream.getWriter(); | ||
//console.log('[SEND]', line); | ||
await writer.write(line + '\n'); | ||
writer.releaseLock(); | ||
} | ||
sendLine(line: string): void { | ||
this.writeToStream(line); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
17822
295
46