This commit is contained in:
Sergey Yarkov 2022-09-21 00:00:25 +03:00
parent c524b034e1
commit 6e5e770bd8
3 changed files with 100 additions and 87 deletions

View File

@ -1,3 +1,5 @@
var EOT = '\u0004';
class SerialPortHandler { class SerialPortHandler {
constructor(options, onConnect, onDisconnect) { constructor(options, onConnect, onDisconnect) {
this.encoder = new TextEncoder(); this.encoder = new TextEncoder();
@ -11,7 +13,6 @@ class SerialPortHandler {
} }
async open() { async open() {
if ('serial' in navigator) {
try { try {
const port = await navigator.serial.requestPort(); const port = await navigator.serial.requestPort();
await port.open(this.options); await port.open(this.options);
@ -24,9 +25,6 @@ class SerialPortHandler {
console.error(error); console.error(error);
throw error; throw error;
} }
} else {
console.error('Web Serial API is not supported in your browser.');
}
} }
async close() { async close() {
@ -43,96 +41,111 @@ class SerialPortHandler {
async read() { async read() {
const reader = this.port.readable.getReader(); const reader = this.port.readable.getReader();
const chunks = []; let chunks = '';
while (true) { while (true) {
const { value, done } = await reader.read(); const { value, done } = await reader.read();
const decoded = this.decoder.decode(value); const decoded = this.decoder.decode(value);
chunks.push(decoded); chunks += decoded;
if (done || decoded.includes('\u0004')) { if (done || decoded.includes('\u0004')) {
console.log('done'); console.log('Reading done.');
reader.releaseLock(); reader.releaseLock();
break; break;
} }
} }
return chunks.join(''); return chunks;
} }
#setupListeners() { #setupListeners() {
if ('serial' in navigator) {
navigator.serial.addEventListener('connect', this.onConnect); navigator.serial.addEventListener('connect', this.onConnect);
navigator.serial.addEventListener('disconnect', this.onDisconnected); navigator.serial.addEventListener('disconnect', this.onDisconnected);
} }
}
} }
const $connectButton = document.getElementById('connect'); class Application {
const $disconnectButton = document.getElementById('disconnect'); constructor(root) {
const $terminalForm = document.getElementById('terminal_form'); if (!('serial' in navigator)) {
const $serialLog = document.getElementById('serial_log'); console.error('Web Serial API is not supported in your browser.');
const $status = document.getElementById('status'); return;
const $vendorId = document.getElementById('vendorId'); }
const $productId = document.getElementById('productId');
const onConnected = (e) => console.log('device inserted!'); this.serialPortHandler = new SerialPortHandler({ baudRate: 9600 });
const onDisconnected = (e) => console.log('device ejected!');
const serialPortHandler = new SerialPortHandler( /**
{ baudRate: 9600 }, * DOM Elements
onConnected, */
onDisconnected this.$root = root;
); this.$connectButton = this.$root.querySelector('#connect');
this.$disconnectButton = this.$root.querySelector('#disconnect');
this.$terminalForm = this.$root.querySelector('#terminal_form');
this.$serialLog = this.$root.querySelector('#serial_log');
this.$status = this.$root.querySelector('#status');
this.$vendorId = this.$root.querySelector('#vendorId');
this.$productId = this.$root.querySelector('#productId');
async function onConnect() { this.#setupEvents();
}
/**
* Handlers for connecting, disconnecting and sending a command
*/
#setupEvents() {
this.$connectButton.addEventListener('click', this.#connectHandler.bind(this));
this.$disconnectButton.addEventListener('click', this.#disconnectHandler.bind(this));
this.$terminalForm.addEventListener('submit', this.#submitHandler.bind(this));
}
/**
* Open serial port and notify user of connection status
* @returns {Promise<void>}
*/
async #connectHandler() {
try { try {
if (serialPortHandler.isOpened) return; if (this.serialPortHandler.isOpened) return;
const info = await serialPortHandler.open(); const info = await this.serialPortHandler.open();
console.log('Port opened: ', info); console.log('Port opened: ', info);
$terminalForm.elements.input.removeAttribute('disabled'); this.$terminalForm.elements.input.removeAttribute('disabled');
$vendorId.textContent = '0x' + info.usbVendorId.toString(16); this.$vendorId.textContent = '0x' + info.usbVendorId.toString(16);
$productId.textContent = '0x' + info.usbProductId.toString(16); this.$productId.textContent = '0x' + info.usbProductId.toString(16);
$status.textContent = 'CONNECTED'; this.$status.textContent = 'CONNECTED';
} catch (error) { } catch (error) {
$status.textContent = 'ERROR'; this.$status.textContent = 'ERROR';
}
} }
}
async function onDisconnect() { /**
if (!serialPortHandler.isOpened) return; * Closes the serial port and updates the connection status.
await serialPortHandler.close(); * @returns {Promise<void>}
$vendorId.textContent = '-'; */
$productId.textContent = '-'; async #disconnectHandler() {
$status.textContent = 'NOT CONNECTED'; if (!this.serialPortHandler.isOpened) return;
} await this.serialPortHandler.close();
this.$vendorId.textContent = '-';
this.$productId.textContent = '-';
this.$status.textContent = 'NOT CONNECTED';
}
async function onSend(e) { /**
* Writes data to the serial port and reads the response
* @param {SubmitEvent} e - Form submit event
*/
async #submitHandler(e) {
e.preventDefault(); e.preventDefault();
const $form = e.target; const $form = e.target;
const data = $form.elements.input.value; const data = $form.elements.input.value;
$form.reset(); $form.reset();
if (serialPortHandler.isOpened && data) { if (this.serialPortHandler.isOpened && data) {
$serialLog.innerHTML += data + '\n'; this.$serialLog.innerHTML += data + '\n';
await serialPortHandler.write(data + '\n'); await this.serialPortHandler.write(data + '\n');
const message = await serialPortHandler.read(); const message = await this.serialPortHandler.read();
$serialLog.textContent += message; this.$serialLog.textContent += message;
$serialLog.textContent += '\n'; this.$serialLog.textContent += '\n';
console.log(message); console.log(message);
} }
$serialLog.scrollTo(0, $serialLog.scrollHeight); this.$serialLog.scrollTo(0, this.$serialLog.scrollHeight);
}
} }
$connectButton.addEventListener('click', onConnect); new Application(document.getElementById('app'));
$disconnectButton.addEventListener('click', onDisconnect);
$terminalForm.addEventListener('submit', onSend);
// const program1 = setInterval(async () => {
// if (serialPortHandler.isOpened) {
// await serialPortHandler.write('led_toggle' + '\n');
// }
// }, 50);
// setInterval(() => {
// clearInterval(program1);
// }, 5000);

View File

@ -9,7 +9,7 @@
<script defer src="./app.js"></script> <script defer src="./app.js"></script>
</head> </head>
<body> <body>
<div class="app"> <div id="app">
<div> <div>
<button id="connect">Connect</button> <button id="connect">Connect</button>
<button id="disconnect">Disconnect</button> <button id="disconnect">Disconnect</button>

View File

@ -10,7 +10,7 @@
box-sizing: inherit; box-sizing: inherit;
} }
.app { #app {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
/* padding: 20px; */ /* padding: 20px; */