From 9431a100c4a152aefa53fbcd7d59d3d201af42ee Mon Sep 17 00:00:00 2001 From: byun Date: Sat, 24 Jan 2026 18:28:04 +0000 Subject: [PATCH] =?UTF-8?q?dot=20=EC=88=98=EC=A0=95=20=EC=8B=A0=ED=98=B8?= =?UTF-8?q?=20sync?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- graph_viewer.h | 87 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/graph_viewer.h b/graph_viewer.h index 3b94814..393de05 100644 --- a/graph_viewer.h +++ b/graph_viewer.h @@ -290,6 +290,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( let rangeMode = '10s'; let totalMsgReceived = 0; let lastCanCounts = {}; // ★ 각 CAN ID별 마지막 count 저장 + let lastSignalTimes = {}; // ⭐ 각 신호별 마지막 시간 저장 (time-base 모드용) const COLORS = [ {line: '#FF6384', fill: 'rgba(255, 99, 132, 0.2)'}, @@ -360,7 +361,14 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( this.labels.shift(); this.rawValues.shift(); } - + } + + // ⭐ 배치 데이터 추가 (500ms 동안 받은 모든 데이터) + addDataBatch(values, times) { + values.forEach((value, index) => { + this.addData(value, times[index]); + }); + // 배치 추가 후 한 번만 그리기 this.draw(); } @@ -379,16 +387,17 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( const graphWidth = this.width - padding * 2; const graphHeight = this.height - padding * 2; - ctx.clearRect(0, 0, this.width, this.height); + ctx.fillStyle = '#1a1a1a'; + ctx.fillRect(0, 0, this.width, this.height); let displayData = []; let displayTimes = []; let displayLabels = []; if (rangeMode === '10s') { - const currentTime = this.times[this.times.length - 1]; + const currentTime = parseFloat(this.times[this.times.length - 1]); for (let i = 0; i < this.times.length; i++) { - if (currentTime - this.times[i] <= 10) { + if (currentTime - parseFloat(this.times[i]) <= 10) { displayData.push(this.data[i]); displayTimes.push(this.times[i]); displayLabels.push(this.labels[i]); @@ -408,20 +417,20 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( let minTime, maxTime, timeRange; if (scaleMode === 'time') { - minTime = displayTimes[0]; - maxTime = displayTimes[displayTimes.length - 1]; + minTime = parseFloat(displayTimes[0]); + maxTime = parseFloat(displayTimes[displayTimes.length - 1]); timeRange = maxTime - minTime || 1; } - ctx.strokeStyle = '#444'; - ctx.lineWidth = 1; + ctx.strokeStyle = '#888'; + ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(padding, padding); ctx.lineTo(padding, this.height - padding); ctx.lineTo(this.width - padding, this.height - padding); ctx.stroke(); - ctx.fillStyle = '#aaa'; + ctx.fillStyle = '#ccc'; ctx.font = '11px Arial'; ctx.textAlign = 'right'; @@ -443,7 +452,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( } ctx.textAlign = 'center'; - ctx.fillStyle = '#aaa'; + ctx.fillStyle = '#ccc'; ctx.font = '10px Arial'; if (displayLabels.length > 0) { ctx.fillText(displayLabels[0] + 's', padding, this.height - padding + 15); @@ -460,7 +469,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( } ctx.fillText('Time (sec)', this.width / 2, this.height - 5); - ctx.strokeStyle = '#333'; + ctx.strokeStyle = '#444'; ctx.lineWidth = 1; for (let i = 1; i < 5; i++) { const y = padding + (graphHeight / 5) * i; @@ -477,7 +486,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( let x; if (scaleMode === 'time') { - const timePos = (displayTimes[i] - minTime) / timeRange; + const timePos = (parseFloat(displayTimes[i]) - minTime) / timeRange; x = padding + graphWidth * timePos; } else { x = padding + (graphWidth / (MAX_DATA_POINTS - 1)) * i; @@ -675,11 +684,20 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( // ★★★ 새로운 함수: update 타입 메시지 처리 // 서버가 보내는 형식: {id: 숫자, dlc: 숫자, data: [배열], count: 숫자} - // ★★★ count가 증가한 경우에만 그래프에 데이터 추가 + // ★★★ count 차이만큼 배치로 데이터 추가 (500ms 동안 받은 모든 신호) function processCANDataFromUpdate(messages) { const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(1); const sortedSignals = sortSignalsForDisplay(); + // ⭐ 신호별로 데이터를 모을 배치 객체 + const signalBatches = {}; + sortedSignals.forEach((signal, index) => { + signalBatches[index] = { + values: [], + times: [] + }; + }); + let processedCount = 0; messages.forEach(canMsg => { @@ -694,18 +712,19 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( msgId = msgId & 0x1FFFFFFF; } - // ★ count가 증가한 경우에만 처리 (새로운 CAN 메시지가 있을 때만) + // ★ count 차이 계산 (500ms 동안 몇 개의 메시지가 왔는지) const prevCount = lastCanCounts[msgId] || 0; const currentCount = canMsg.count || 0; + const countDiff = currentCount - prevCount; - if (currentCount <= prevCount) { + if (countDiff <= 0) { // count가 증가하지 않았으면 스킵 return; } // count 업데이트 lastCanCounts[msgId] = currentCount; - totalMsgReceived++; + totalMsgReceived += countDiff; // data가 배열로 오는 경우 HEX 문자열로 변환 let hexData = ''; @@ -720,7 +739,27 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( try { const value = decodeSignalFromHex(signal, hexData); - charts[index].addData(value, elapsedTime); + // ⭐ 신호별 시간 간격 계산 + const signalKey = `${msgId}_${signal.name}`; + const lastTime = lastSignalTimes[signalKey] || 0; + const currentTime = parseFloat(elapsedTime); + const timeDelta = currentTime - lastTime; + + // ⭐ 배치에 데이터 추가 (count 차이만큼, 각각 고유한 시간) + // 예: 10ms 주기 신호가 500ms 동안 50개 왔으면 + // countDiff = 50 + // 각 데이터를 시간 간격에 맞춰 분산 + for (let i = 0; i < countDiff; i++) { + signalBatches[index].values.push(value); + + // ⭐ 시간 분산: 500ms 동안 50개면 10ms 간격 + const timeOffset = (timeDelta / countDiff) * i; + const dataTime = (lastTime + timeOffset).toFixed(3); + signalBatches[index].times.push(dataTime); + } + + // 마지막 시간 업데이트 + lastSignalTimes[signalKey] = currentTime; const valueDiv = document.getElementById('value-' + index); if (valueDiv) { @@ -731,7 +770,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( } } - processedCount++; + processedCount += countDiff; } catch(e) { console.error('Error decoding signal ' + signal.name + ':', e); } @@ -739,8 +778,18 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( }); }); + // ⭐ 배치 데이터를 차트에 한 번에 추가 + sortedSignals.forEach((signal, index) => { + if (charts[index] && signalBatches[index].values.length > 0) { + charts[index].addDataBatch( + signalBatches[index].values, + signalBatches[index].times + ); + } + }); + if (processedCount > 0) { - console.log('Added', processedCount, 'new data points from update'); + console.log('Added', processedCount, 'new data points from update (batch mode)'); } updateStatistics();