diff --git a/examples/device/webusb_serial/website/application.js b/examples/device/webusb_serial/website/application.js index 090ab5748..376faec44 100644 --- a/examples/device/webusb_serial/website/application.js +++ b/examples/device/webusb_serial/website/application.js @@ -369,7 +369,7 @@ } setStatus(msg, level = 'info') { - console.log(msg); + console.error(msg); uiStatusSpan.textContent = msg; uiStatusSpan.className = 'status status-' + level; } @@ -596,24 +596,33 @@ } } + async autoReconnectTimeout() { + this.reconnectTimeoutId = null; + if (!uiAutoReconnectCheckbox.checked) { + this.setStatus('Auto-reconnect stopped.', 'info'); + return; + } + if (this.currentPort && !this.currentPort.isConnected) { + try { + await this.currentPort.connect(); + this.setStatus('Reconnected successfully', 'info'); + } catch (error) { + this.setStatus(`Reconnect failed: ${error.message}`, 'error'); + // Try again after a delay + this.tryAutoReconnect(); + } finally { + this.updateUIConnectionState(); + } + } + } + tryAutoReconnect() { this.updateUIConnectionState(); if (!uiAutoReconnectCheckbox.checked) return; if (this.reconnectTimeoutId !== null) return; // already trying this.setStatus('Attempting to auto-reconnect...', 'info'); this.reconnectTimeoutId = setTimeout(async () => { - this.reconnectTimeoutId = null; - if (!uiAutoReconnectCheckbox.checked) { - this.setStatus('Auto-reconnect stopped.', 'info'); - return; - } - if (this.currentPort) { - try { - await this.currentPort.connect(); - } finally { - this.updateUIConnectionState(); - } - } + await this.autoReconnectTimeout(); }, 1000); } @@ -762,14 +771,15 @@ // save , let csvContent = 'data:text/csv;charset=utf-8,'; for (const entry of this.receivedData) { - let line = new Date(entry.time).toISOString() + ',"' + entry.text.replace(/[\r\n]+$/, '') + '"'; + let sanitizedText = entry.text.replace(/"/g, '""').replace(/[\r\n]+$/, ''); + let line = new Date(entry.time).toISOString() + ',"' + sanitizedText + '"'; csvContent += line + '\n'; } const encodedUri = encodeURI(csvContent); const link = document.createElement('a'); link.setAttribute('href', encodedUri); - const filename = new Date().toISOString() + '_tinyusb_received_serial_data.csv'; + const filename = new Date().toISOString().replace(/:/g, '-') + '_tinyusb_received_serial_data.csv'; link.setAttribute('download', filename); document.body.appendChild(link); link.click(); diff --git a/examples/device/webusb_serial/website/index.html b/examples/device/webusb_serial/website/index.html index bf02d0294..60002ff0a 100644 --- a/examples/device/webusb_serial/website/index.html +++ b/examples/device/webusb_serial/website/index.html @@ -35,7 +35,7 @@ diff --git a/examples/device/webusb_serial/website/serial.js b/examples/device/webusb_serial/website/serial.js index 55035c81f..19827f016 100644 --- a/examples/device/webusb_serial/website/serial.js +++ b/examples/device/webusb_serial/website/serial.js @@ -116,7 +116,7 @@ class SerialPort { if (!this._port.writable) { throw new Error('Port is not writable'); } - this._writer = port.writeable.getWriter(); + this._writer = this._port.writable.getWriter(); if (!this._writer) { throw new Error('Failed to get writer from port'); } @@ -141,6 +141,13 @@ class WebUsbSerialPort { this._readLoopPromise = null; this._initialized = false; this._keepReading = true; + + this._vendorId = device.vendorId; + this._productId = device.productId; + } + + _isSameWebUsbSerialPort(webUsbSerialPort) { + return this._vendorId === webUsbSerialPort._vendorId && this._productId === webUsbSerialPort._productId; } /// Connect and start reading loop @@ -152,14 +159,9 @@ class WebUsbSerialPort { console.error('Error disconnecting previous device:', error); } - if (this._readLoopPromise) { - try { - await this._readLoopPromise; - } catch (error) { - console.error('Error in read loop:', error); - } - } - this._readLoopPromise = null; + const webUsbSerialPorts = await serial.getWebUsbSerialPorts(); + const webUsbSerialPort = webUsbSerialPorts.find(serialPort => this._isSameWebUsbSerialPort(serialPort)); + this._device = webUsbSerialPort ? webUsbSerialPort._device : this._device; } this._initialized = true; diff --git a/examples/device/webusb_serial/website/style.css b/examples/device/webusb_serial/website/style.css index 3af2668e0..7b8b6029d 100644 --- a/examples/device/webusb_serial/website/style.css +++ b/examples/device/webusb_serial/website/style.css @@ -221,6 +221,12 @@ body.dark-mode { color: #d4d4d4; } +body.dark-mode input[type="checkbox"] { + border-color: #888; + accent-color: #2e2e2e; + opacity: 0.8; +} + body.dark-mode .btn-theme { background-color: #b0b0b0; color: #000; @@ -251,6 +257,7 @@ body.dark-mode .input:focus { body.dark-mode .scrollbox { background-color: #252526; + scrollbar-color: #555 #2e2e2e; border: 1px solid #444; } @@ -287,7 +294,3 @@ body.dark-mode option { background-color: #3c3c3c; color: #f0f0f0; } - -body.dark-mode .scrollbox { - scrollbar-color: #555 #2e2e2e; -}