summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/device/webusb_serial/website/application.js136
-rw-r--r--examples/device/webusb_serial/website/index.html2
2 files changed, 89 insertions, 49 deletions
diff --git a/examples/device/webusb_serial/website/application.js b/examples/device/webusb_serial/website/application.js
index a94a96714..8c01ce111 100644
--- a/examples/device/webusb_serial/website/application.js
+++ b/examples/device/webusb_serial/website/application.js
@@ -25,17 +25,60 @@
let lastCommandCount = 0;
let lastCommandButton = null;
- let sendMode = 'command'; // default mode
+ let sendMode = localStorage.getItem('sendMode') || 'command';
- let reconnectIntervalId = null; // track reconnect interval
+ // track reconnect interval
+ let reconnectIntervalId = null;
- // Format incoming data to string based on newline mode
+ // Append sent command to sender container as a clickable element
+ const appendCommandToSender = (container, text) => {
+ if (text === lastCommand) {
+ // Increment count and update button
+ lastCommandCount++;
+ lastCommandButton.textContent = `${text} ×${lastCommandCount}`;
+ } else {
+ // Reset count and add new button
+ lastCommand = text;
+ lastCommandCount = 1;
+
+ const commandEl = document.createElement('button');
+ commandEl.className = 'sender-entry';
+ commandEl.type = 'button';
+ commandEl.textContent = text;
+ commandEl.addEventListener('click', () => {
+ commandLine.value = text;
+ commandLine.focus();
+ });
+ container.appendChild(commandEl);
+ lastCommandButton = commandEl;
+
+ const distanceFromBottom = container.scrollHeight - (container.scrollTop + container.clientHeight);
+ if (distanceFromBottom < nearTheBottomThreshold) {
+ requestAnimationFrame(() => {
+ commandEl.scrollIntoView({ behavior: 'instant' });
+ });
+ }
+ }
+ };
+
+ // Restore command history
+ history.push(...(JSON.parse(localStorage.getItem('commandHistory') || '[]')));
+ for (const cmd of history) {
+ appendCommandToSender(senderLines, cmd);
+ }
+
+ // Restore auto reconnect checkbox
+ autoReconnectCheckbox.checked = localStorage.getItem('autoReconnect') === 'true';
+ // Restore newline mode
+ const savedNewlineMode = localStorage.getItem('newlineMode');
+ if (savedNewlineMode) newlineModeSelect.value = savedNewlineMode;
+
+ // Format incoming data
const decodeData = (() => {
const decoder = new TextDecoder();
return dataView => decoder.decode(dataView);
})();
- // Normalize newline if mode is ANY
const normalizeNewlines = (text, mode) => {
switch (mode) {
case 'CR':
@@ -67,37 +110,6 @@
}
};
- // Append sent command to sender container as a clickable element
- const appendCommandToSender = (container, text) => {
- if (text === lastCommand) {
- // Increment count and update button
- lastCommandCount++;
- lastCommandButton.textContent = `${text} ×${lastCommandCount}`;
- } else {
- // Reset count and add new button
- lastCommand = text;
- lastCommandCount = 1;
-
- const commandEl = document.createElement('button');
- commandEl.className = 'sender-entry';
- commandEl.type = 'button';
- commandEl.textContent = text;
- commandEl.addEventListener('click', () => {
- commandLine.value = text;
- commandLine.focus();
- });
- container.appendChild(commandEl);
- lastCommandButton = commandEl;
-
- const distanceFromBottom = container.scrollHeight - (container.scrollTop + container.clientHeight);
- if (distanceFromBottom < nearTheBottomThreshold) {
- requestAnimationFrame(() => {
- commandEl.scrollIntoView({ behavior: 'instant' });
- });
- }
- }
- };
-
// Update status text and style
const setStatus = (msg, level = 'info') => {
console.log(msg);
@@ -120,7 +132,7 @@
};
// Connect helper
- const connectPort = async (initial=false) => {
+ const connectPort = async (initial = false) => {
try {
let grantedDevices = await serial.getPorts();
if (grantedDevices.length === 0 && initial) {
@@ -148,24 +160,27 @@
}
await port.connect();
- lastPort = port; // save for reconnecting
+ // save for reconnecting
+ lastPort = port;
setStatus(`Connected to ${port.device.productName || 'device'}`, 'info');
connectBtn.textContent = 'Disconnect';
commandLine.disabled = false;
commandLine.focus();
+ port.onReceiveError = async error => {
+ setStatus(`Read error: ${error.message}`, 'error');
+ await disconnectPort();
+ // Start auto reconnect on error if enabled
+ await tryAutoReconnect();
+ };
+
port.onReceive = dataView => {
let text = decodeData(dataView);
text = normalizeNewlines(text, newlineModeSelect.value);
appendLineToReceiver(receiverLines, text, 'received');
};
- port.onReceiveError = error => {
- setStatus(`Read error: ${error.message}`, 'error');
- // Start auto reconnect on error if enabled
- tryAutoReconnect();
- };
return true;
} catch (error) {
setStatus(`Connection failed: ${error.message}`, 'error');
@@ -177,7 +192,7 @@
};
// Start auto reconnect interval if checkbox is checked and not already running
- const tryAutoReconnect = () => {
+ const tryAutoReconnect = async () => {
if (!autoReconnectCheckbox.checked) return;
if (reconnectIntervalId !== null) return; // already trying
setStatus('Attempting to auto-reconnect...', 'info');
@@ -238,13 +253,16 @@
});
// Checkbox toggle stops auto reconnect if unchecked
- autoReconnectCheckbox.addEventListener('change', () => {
+ autoReconnectCheckbox.addEventListener('change', async () => {
+ localStorage.setItem('autoReconnect', autoReconnectCheckbox.checked);
if (!autoReconnectCheckbox.checked) {
stopAutoReconnect();
} else {
// Start auto reconnect immediately if not connected
- if (!port) {
- tryAutoReconnect();
+ console.log(port);
+ console.log(lastPort);
+ if (!port && lastPort) {
+ await tryAutoReconnect();
}
}
});
@@ -263,8 +281,16 @@
sendModeBtn.classList.add('send-mode-command');
sendModeBtn.textContent = 'Command mode';
}
+ localStorage.setItem('sendMode', sendMode);
});
+ // Set initial sendMode button state
+ if (sendMode === 'instant') {
+ sendModeBtn.classList.remove('send-mode-command');
+ sendModeBtn.classList.add('send-mode-instant');
+ sendModeBtn.textContent = 'Instant mode';
+ }
+
// Send command line input on Enter
commandLine.addEventListener('keydown', async e => {
if (!port) return;
@@ -314,7 +340,8 @@
await port.send(encoder.encode(sendText));
} catch (error) {
setStatus(`Send error: ${error.message}`, 'error');
- tryAutoReconnect();
+ await disconnectPort();
+ await tryAutoReconnect();
}
}
@@ -344,6 +371,7 @@
// Add command to history, ignore duplicate consecutive
if (history.length === 0 || history[history.length - 1] !== text) {
history.push(text);
+ localStorage.setItem('commandHistory', JSON.stringify(history));
}
historyIndex = -1;
@@ -369,10 +397,15 @@
commandLine.value = '';
} catch (error) {
setStatus(`Send error: ${error.message}`, 'error');
- tryAutoReconnect();
+ await disconnectPort();
+ await tryAutoReconnect();
}
});
+ newlineModeSelect.addEventListener('change', () => {
+ localStorage.setItem('newlineMode', newlineModeSelect.value);
+ });
+
// Forget device button clears stored device info
forgetDeviceBtn.addEventListener('click', async () => {
if (port) {
@@ -415,6 +448,13 @@
lastCommand = null;
lastCommandCount = 0;
lastCommandButton = null;
+ history.length = 0;
+ historyIndex = -1;
+
+ // iterate and delete localStorage items
+ for (const key in localStorage) {
+ localStorage.removeItem(key);
+ }
});
diff --git a/examples/device/webusb_serial/website/index.html b/examples/device/webusb_serial/website/index.html
index 91d6e4fba..8d18ff8cf 100644
--- a/examples/device/webusb_serial/website/index.html
+++ b/examples/device/webusb_serial/website/index.html
@@ -50,7 +50,7 @@
<div id="sender_lines" class="scrollbox monospaced"></div>
</div>
<div class="send-container">
- <input id="command_line" class="input" placeholder="Start typing..." />
+ <input id="command_line" class="input" placeholder="Start typing..." autocomplete="off" />
<button id="send_mode" class="btn send-mode-command">Command Mode</button>
</div>
</section>