diff --git a/web/app.js b/web/app.js index b4debf6..6d5711f 100644 --- a/web/app.js +++ b/web/app.js @@ -1,5 +1,110 @@ -const $connectButton = document.getElementById('MCU_connect'); +class SerialPortHandler { + constructor(options) { + this.encoder = new TextEncoder(); + this.decoder = new TextDecoder(); + this.options = options; + this.port = null; + this.writer = null; + this.reader = null; + this.isOpened = false; + } -console.log($connectButton); + async open() { + if ('serial' in navigator) { + try { + const port = await navigator.serial.requestPort(); + await port.open(this.options); -// ... + this.port = port; + this.writer = port.writable.getWriter(); + this.reader = port.readable.getReader(); + this.isOpened = true; + + return this.port.getInfo(); + } catch (error) { + console.error(error); + throw error; + } + } else { + console.error('Web Serial API is not supported in your browser.'); + } + } + + async close() { + await this.port.close(); + } + + async write(data) { + const encoded = this.encoder.encode(data); + return await this.writer.write(encoded); + } + + async read() { + let data = ''; + while (true) { + const { value, done } = await this.reader.read(); + if (done) { + this.reader.releaseLock(); + break; + } + data += this.decoder.decode(value); + console.log(data); + } + } +} + +const $connectButton = document.getElementById('connect'); +const $disconnectButton = document.getElementById('disconnect'); +const $terminalForm = document.getElementById('terminal_form'); +const $serialLog = document.getElementById('serial_log'); +const $status = document.getElementById('status'); +const $vendorId = document.getElementById('vendorId'); +const $productId = document.getElementById('productId'); + +const serialPortHandler = new SerialPortHandler({ baudRate: 9600 }); + +async function onConnect() { + try { + const info = await serialPortHandler.open(); + console.log('Device connected: ', info); + console.log(serialPortHandler.port); + $terminalForm.elements.input.removeAttribute('disabled'); + $vendorId.textContent = '0x' + info.usbVendorId.toString(16); + $productId.textContent = '0x' + info.usbProductId.toString(16); + $status.textContent = 'CONNECTED'; + } catch (error) { + $status.textContent = 'ERROR'; + } +} + +async function onDisconnect() { + await serialPortHandler.close(); + $vendorId.textContent = '-'; + $productId.textContent = '-'; + $status.textContent = 'NOT CONNECTED'; +} + +async function onSend(e) { + e.preventDefault(); + const $form = e.target; + const data = $form.elements.input.value; + $form.reset(); + if (serialPortHandler.isOpened) { + await serialPortHandler.write(data + '\n'); + await serialPortHandler.read(); + } +} + +$connectButton.addEventListener('click', onConnect); +$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); diff --git a/web/index.html b/web/index.html index 772b38e..ed0a924 100644 --- a/web/index.html +++ b/web/index.html @@ -4,10 +4,39 @@ - Document + Web Serial API Example + - +
+
+ + +
+
+
+
+ + +
+
+ +
+
+

not connected

+
+
+ vendorId: - | + deviceId: - +
+
+
diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..367913b --- /dev/null +++ b/web/style.css @@ -0,0 +1,93 @@ +:root { + --border-color: #c9d1d9; + --border-color-hover: #6e7681; + --font-family: monospace; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +.app { + display: flex; + flex-direction: column; + /* padding: 20px; */ + width: 100%; + max-width: 600px; + row-gap: 5px; +} + +html, +body { + box-sizing: border-box; + font-size: 16px; +} + +body { + display: flex; + justify-content: center; + margin-top: 2rem; + font-family: var(--font-family); +} + +p { + padding: 0; + margin: 5px; +} + +input, +textarea { + font-family: var(--font-family); + padding: 5px 15px; + border-radius: 4px; + width: 100%; + border: 1px solid var(--border-color); +} + +textarea { + resize: vertical; + min-height: 200px; + font-size: 16px; + outline: none; + font-size: 12px; +} + +label { + font-size: 14px; + font-style: italic; +} + +button { + cursor: pointer; + background: none; + font-family: var(--font-family); + border: 1px solid var(--border-color); + border-radius: 4px; + padding: 5px 15px; +} + +button:hover { + border: 1px solid var(--border-color-hover); +} + +#terminal_form div { + display: flex; + justify-content: space-between; + gap: 5px; + margin-bottom: 5px; + margin-top: 5px; +} + +#port_info { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + font-size: 14px; +} + +#port_info #status { + text-transform: uppercase; +}