From 750bea70ec9ac25c88f2e4e828177e1a47406a22 Mon Sep 17 00:00:00 2001 From: roy01 Date: Thu, 4 Jun 2026 15:53:42 +0800 Subject: [PATCH] feat: enhance download functionality with selectable log types and command history management --- uart_example/app.js | 88 +++++++++++++++++++++++++++++++++++++---- uart_example/index.css | 54 +++++++++++++++++++++++++ uart_example/index.html | 58 ++++++++++++++++++--------- 3 files changed, 174 insertions(+), 26 deletions(-) diff --git a/uart_example/app.js b/uart_example/app.js index c5cf1e2..6b72d3e 100644 --- a/uart_example/app.js +++ b/uart_example/app.js @@ -24,6 +24,7 @@ const sendBtn = document.getElementById('send-btn'); const clearBtn = document.getElementById('clear-btn'); const addSessionBtn = document.getElementById('add-session-btn'); const sessionListContainer = document.getElementById('session-list'); +const downloadTypeSelect = document.getElementById('download-type'); // PortSession Class definition class PortSession { @@ -36,7 +37,12 @@ class PortSession { this.reader = null; this.writer = null; this.keepReading = false; - this.receivedLogBuffer = []; + this.rxLogBuffer = []; + this.txLogBuffer = []; + this.combinedLogBuffer = []; + this.downloadType = 'rx_tx'; + this.commandHistory = []; + this.historyIndex = -1; this.isTerminalEmpty = true; this.deviceInfo = ''; @@ -113,6 +119,10 @@ document.addEventListener('DOMContentLoaded', () => { if (activeSession) activeSession.sendText = sendInput.value; }); + downloadTypeSelect.addEventListener('change', () => { + if (activeSession) activeSession.downloadType = downloadTypeSelect.value; + }); + // Initialize with a default session addSession(); }); @@ -237,8 +247,9 @@ function selectSession(session) { sendFormatSelect.value = activeSession.sendFormat; sendEolSelect.value = activeSession.sendEol; sendInput.value = activeSession.sendText; + downloadTypeSelect.value = activeSession.downloadType; - downloadBtn.disabled = activeSession.isTerminalEmpty; + downloadBtn.disabled = (activeSession.rxLogBuffer.length === 0 && activeSession.txLogBuffer.length === 0); // Sync status banner and buttons const isConnected = activeSession.port !== null && activeSession.port.readable; @@ -485,7 +496,8 @@ function handleIncomingSessionData(session, uint8Array, decoder) { formattedText = decoder.decode(uint8Array); } - session.receivedLogBuffer.push(formattedText); + session.rxLogBuffer.push(formattedText); + session.combinedLogBuffer.push(formattedText); appendSessionTerminalText(session, formattedText, 'received'); } @@ -504,6 +516,19 @@ async function sendSessionData() { const rawInput = sendInput.value; if (!rawInput) return; + // Add command to history (maximum 10 items) + const trimmed = rawInput.trim(); + if (trimmed) { + const history = session.commandHistory; + if (history.length === 0 || history[history.length - 1] !== trimmed) { + history.push(trimmed); + if (history.length > 10) { + history.shift(); + } + } + session.historyIndex = history.length; + } + const format = session.sendFormat; const eol = session.sendEol; let bytesToSend; @@ -552,6 +577,11 @@ async function sendSessionData() { } appendSessionTerminalText(session, `\n[Sent] ${displaySent}\n`, 'sent'); + + // Save sent log + session.txLogBuffer.push(`[Sent] ${displaySent}\n`); + session.combinedLogBuffer.push(`\n[Sent] ${displaySent}\n`); + sendInput.value = ''; session.sendText = ''; @@ -614,15 +644,35 @@ function clearTerminal() { activeSession.terminalOutputElement.innerHTML = 'No data received yet...'; activeSession.terminalOutputElement.classList.add('empty'); activeSession.isTerminalEmpty = true; - activeSession.receivedLogBuffer = []; + activeSession.rxLogBuffer = []; + activeSession.txLogBuffer = []; + activeSession.combinedLogBuffer = []; downloadBtn.disabled = true; showToast('Terminal cleared.', 'success'); } function downloadLog() { - if (!activeSession || activeSession.receivedLogBuffer.length === 0) return; + if (!activeSession) return; + + let content = ''; + let filenameSuffix = ''; + + if (activeSession.downloadType === 'rx') { + content = activeSession.rxLogBuffer.join(''); + filenameSuffix = 'rx'; + } else if (activeSession.downloadType === 'tx') { + content = activeSession.txLogBuffer.join(''); + filenameSuffix = 'tx'; + } else { + content = activeSession.combinedLogBuffer.join(''); + filenameSuffix = 'combined'; + } + + if (!content) { + showToast('No logs to download for the selected type.', 'error'); + return; + } - const content = activeSession.receivedLogBuffer.join(''); const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); @@ -630,7 +680,7 @@ function downloadLog() { const a = document.createElement('a'); a.href = url; - a.download = `uart_log_${activeSession.name.replace(/\s+/g, '_')}_${dateStr}.txt`; + a.download = `uart_log_${activeSession.name.replace(/\s+/g, '_')}_${filenameSuffix}_${dateStr}.txt`; document.body.appendChild(a); a.click(); @@ -664,6 +714,30 @@ sendInput.addEventListener('keydown', (e) => { e.preventDefault(); sendSessionData(); } + if (e.key === 'ArrowUp') { + e.preventDefault(); + if (activeSession && activeSession.commandHistory.length > 0) { + if (activeSession.historyIndex > 0) { + activeSession.historyIndex--; + sendInput.value = activeSession.commandHistory[activeSession.historyIndex]; + activeSession.sendText = sendInput.value; + } + } + } + if (e.key === 'ArrowDown') { + e.preventDefault(); + if (activeSession && activeSession.commandHistory.length > 0) { + if (activeSession.historyIndex < activeSession.commandHistory.length - 1) { + activeSession.historyIndex++; + sendInput.value = activeSession.commandHistory[activeSession.historyIndex]; + activeSession.sendText = sendInput.value; + } else { + activeSession.historyIndex = activeSession.commandHistory.length; + sendInput.value = ''; + activeSession.sendText = ''; + } + } + } if (e.key === 'Tab' && e.ctrlKey) { e.preventDefault(); const start = sendInput.selectionStart; diff --git a/uart_example/index.css b/uart_example/index.css index c56782f..081a215 100644 --- a/uart_example/index.css +++ b/uart_example/index.css @@ -896,3 +896,57 @@ body.light-theme .session-item.active { .hidden { display: none !important; } + +/* Download Group Control Styling */ +.download-group { + display: flex; + align-items: center; + gap: 0.25rem; + background-color: var(--bg-input); + border: 1px solid var(--border-color); + border-radius: var(--radius-md); + padding: 3px 6px 3px 3px; + height: 48px; + box-shadow: var(--shadow-sm); + transition: border-color var(--transition-fast), background-color var(--transition-fast); +} + +.download-group:hover { + border-color: var(--border-hover); +} + +.download-group .download-btn { + height: 40px; + width: 40px; + border-radius: 6px; + box-shadow: none; +} + +.download-group .download-btn:hover:not(:disabled) { + transform: none; +} + +.download-select-wrapper { + width: 105px; + flex-shrink: 0; +} + +.download-select-wrapper select { + background-color: transparent !important; + border: none !important; + padding: 0.4rem 1.75rem 0.4rem 0.5rem !important; + font-weight: 600; + font-size: 0.85rem; + color: var(--text-main); + box-shadow: none !important; +} + +.download-select-wrapper select option { + background-color: var(--bg-panel); + color: var(--text-main); +} + +.download-select-wrapper::after { + right: 0.5rem; +} + diff --git a/uart_example/index.html b/uart_example/index.html index 81a2d1e..318be71 100644 --- a/uart_example/index.html +++ b/uart_example/index.html @@ -1,5 +1,6 @@ + @@ -7,9 +8,12 @@ - + +
@@ -17,7 +21,8 @@

UART Terminal

@@ -43,7 +49,8 @@

Sessions

- - +
+ +
+ +
+
- + @@ -188,7 +205,7 @@
- +