diff --git a/web/app.js b/web/app.js index 406966e..47f683f 100644 --- a/web/app.js +++ b/web/app.js @@ -1,3 +1,5 @@ +var EOT = '\u0004'; + class SerialPortHandler { constructor(options, onConnect, onDisconnect) { this.encoder = new TextEncoder(); @@ -11,21 +13,17 @@ class SerialPortHandler { } async open() { - if ('serial' in navigator) { - try { - const port = await navigator.serial.requestPort(); - await port.open(this.options); + try { + const port = await navigator.serial.requestPort(); + await port.open(this.options); - this.port = port; - this.isOpened = true; + this.port = port; + 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.'); + return this.port.getInfo(); + } catch (error) { + console.error(error); + throw error; } } @@ -43,96 +41,111 @@ class SerialPortHandler { async read() { const reader = this.port.readable.getReader(); - const chunks = []; + let chunks = ''; while (true) { const { value, done } = await reader.read(); const decoded = this.decoder.decode(value); - chunks.push(decoded); + chunks += decoded; if (done || decoded.includes('\u0004')) { - console.log('done'); + console.log('Reading done.'); reader.releaseLock(); break; } } - return chunks.join(''); + return chunks; } #setupListeners() { - if ('serial' in navigator) { - navigator.serial.addEventListener('connect', this.onConnect); - navigator.serial.addEventListener('disconnect', this.onDisconnected); + navigator.serial.addEventListener('connect', this.onConnect); + navigator.serial.addEventListener('disconnect', this.onDisconnected); + } +} + +class Application { + constructor(root) { + if (!('serial' in navigator)) { + console.error('Web Serial API is not supported in your browser.'); + return; + } + + this.serialPortHandler = new SerialPortHandler({ baudRate: 9600 }); + + /** + * DOM Elements + */ + 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'); + + 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} + */ + async #connectHandler() { + try { + if (this.serialPortHandler.isOpened) return; + const info = await this.serialPortHandler.open(); + console.log('Port opened: ', info); + this.$terminalForm.elements.input.removeAttribute('disabled'); + this.$vendorId.textContent = '0x' + info.usbVendorId.toString(16); + this.$productId.textContent = '0x' + info.usbProductId.toString(16); + this.$status.textContent = 'CONNECTED'; + } catch (error) { + this.$status.textContent = 'ERROR'; } } -} -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'); + /** + * Closes the serial port and updates the connection status. + * @returns {Promise} + */ + async #disconnectHandler() { + if (!this.serialPortHandler.isOpened) return; + await this.serialPortHandler.close(); + this.$vendorId.textContent = '-'; + this.$productId.textContent = '-'; + this.$status.textContent = 'NOT CONNECTED'; + } -const onConnected = (e) => console.log('device inserted!'); -const onDisconnected = (e) => console.log('device ejected!'); - -const serialPortHandler = new SerialPortHandler( - { baudRate: 9600 }, - onConnected, - onDisconnected -); - -async function onConnect() { - try { - if (serialPortHandler.isOpened) return; - const info = await serialPortHandler.open(); - console.log('Port opened: ', info); - $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'; + /** + * Writes data to the serial port and reads the response + * @param {SubmitEvent} e - Form submit event + */ + async #submitHandler(e) { + e.preventDefault(); + const $form = e.target; + const data = $form.elements.input.value; + $form.reset(); + if (this.serialPortHandler.isOpened && data) { + this.$serialLog.innerHTML += data + '\n'; + await this.serialPortHandler.write(data + '\n'); + const message = await this.serialPortHandler.read(); + this.$serialLog.textContent += message; + this.$serialLog.textContent += '\n'; + console.log(message); + } + this.$serialLog.scrollTo(0, this.$serialLog.scrollHeight); } } -async function onDisconnect() { - if (!serialPortHandler.isOpened) return; - 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 && data) { - $serialLog.innerHTML += data + '\n'; - await serialPortHandler.write(data + '\n'); - const message = await serialPortHandler.read(); - $serialLog.textContent += message; - $serialLog.textContent += '\n'; - console.log(message); - } - $serialLog.scrollTo(0, $serialLog.scrollHeight); -} - -$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); +new Application(document.getElementById('app')); diff --git a/web/index.html b/web/index.html index ed0a924..24665ce 100644 --- a/web/index.html +++ b/web/index.html @@ -9,7 +9,7 @@ -
+
diff --git a/web/style.css b/web/style.css index 367913b..26c56f2 100644 --- a/web/style.css +++ b/web/style.css @@ -10,7 +10,7 @@ box-sizing: inherit; } -.app { +#app { display: flex; flex-direction: column; /* padding: 20px; */