그래프 수신 시만 dot, monitor창 수신시만 표현

This commit is contained in:
2025-10-07 17:04:20 +00:00
parent 16e0ba1c85
commit da51fafd5a
2 changed files with 54 additions and 53 deletions

View File

@@ -106,7 +106,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
</head>
<body>
<div class="header">
<h1>Real-time CAN Signal Graphs</h1>
<h1>Real-time CAN Signal Graphs (Scatter Mode)</h1>
</div>
<div class="controls">
@@ -126,6 +126,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
let startTime = 0;
let selectedSignals = [];
let dbcData = {};
let lastTimestamps = {}; // 각 신호의 마지막 타임스탬프 추적
const MAX_DATA_POINTS = 60;
const COLORS = [
{line: '#FF6384', fill: 'rgba(255, 99, 132, 0.2)'},
@@ -196,14 +197,14 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
ctx.lineTo(this.width - padding, this.height - padding);
ctx.stroke();
// Y축 라벨
// Y축 레이블
ctx.fillStyle = '#aaa';
ctx.font = '11px Arial';
ctx.textAlign = 'right';
ctx.fillText(maxValue.toFixed(2), padding - 5, padding + 5);
ctx.fillText(minValue.toFixed(2), padding - 5, this.height - padding);
// X축 라벨
// X축 레이블
ctx.textAlign = 'center';
ctx.fillStyle = '#aaa';
ctx.font = '10px Arial';
@@ -229,50 +230,23 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
ctx.stroke();
}
if (this.data.length < 2) return;
if (this.data.length < 1) return;
// 영역 채우기
ctx.fillStyle = this.colors.fill;
ctx.beginPath();
ctx.moveTo(padding, this.height - padding);
for (let i = 0; i < this.data.length; i++) {
const x = padding + (graphWidth / (MAX_DATA_POINTS - 1)) * i;
const y = this.height - padding - ((this.data[i] - minValue) / range) * graphHeight;
ctx.lineTo(x, y);
}
ctx.lineTo(padding + (graphWidth / (MAX_DATA_POINTS - 1)) * (this.data.length - 1), this.height - padding);
ctx.closePath();
ctx.fill();
// 선
ctx.strokeStyle = this.colors.line;
ctx.lineWidth = 2;
ctx.beginPath();
for (let i = 0; i < this.data.length; i++) {
const x = padding + (graphWidth / (MAX_DATA_POINTS - 1)) * i;
const y = this.height - padding - ((this.data[i] - minValue) / range) * graphHeight;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
// 포인트
// 점만 그리기 (선과 영역 채우기 제거)
ctx.fillStyle = this.colors.line;
for (let i = 0; i < this.data.length; i++) {
const x = padding + (graphWidth / (MAX_DATA_POINTS - 1)) * i;
const y = this.height - padding - ((this.data[i] - minValue) / range) * graphHeight;
// 점 크기를 5로 증가 (더 잘 보이도록)
ctx.beginPath();
ctx.arc(x, y, 2, 0, Math.PI * 2);
ctx.arc(x, y, 5, 0, Math.PI * 2);
ctx.fill();
// 점 테두리 추가 (더 선명하게)
ctx.strokeStyle = '#fff';
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
@@ -375,6 +349,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
if (!graphing) {
graphing = true;
startTime = Date.now();
lastTimestamps = {}; // 타임스탬프 초기화
updateStatus('Graphing...', false);
}
}
@@ -390,16 +365,26 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
messages.forEach(canMsg => {
const idStr = canMsg.id.replace(/\s/g, '').toUpperCase();
const msgId = parseInt(idStr, 16);
const timestamp = canMsg.timestamp;
selectedSignals.forEach((signal, index) => {
if (signal.messageId === msgId && charts[index]) {
try {
const value = decodeSignal(signal, canMsg.data);
charts[index].addData(value, elapsedTime);
// 신호별 고유 키 생성
const signalKey = msgId + '_' + signal.name;
const valueDiv = document.getElementById('value-' + index);
if (valueDiv) {
valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : '');
// 이전 타임스탬프와 비교 - 새로운 메시지일 때만 점 추가
if (!lastTimestamps[signalKey] || lastTimestamps[signalKey] !== timestamp) {
const value = decodeSignal(signal, canMsg.data);
charts[index].addData(value, elapsedTime);
// 타임스탬프 업데이트
lastTimestamps[signalKey] = timestamp;
const valueDiv = document.getElementById('value-' + index);
if (valueDiv) {
valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : '');
}
}
} catch(e) {
console.error('Error decoding signal:', e);

34
index.h
View File

@@ -275,10 +275,11 @@ const char index_html[] PROGMEM = R"rawliteral(
let canMessages = {};
let messageOrder = [];
// CAN 속도 이름 매핑
// 마지막 업데이트 추적용
let lastMessageData = {};
const speedNames = ['125 Kbps', '250 Kbps', '500 Kbps', '1 Mbps'];
// CAN 속도 설정 저장
function saveCanSpeed() {
const speed = document.getElementById('can-speed').value;
try {
@@ -289,7 +290,6 @@ const char index_html[] PROGMEM = R"rawliteral(
}
}
// CAN 속도 설정 복원
function loadCanSpeed() {
try {
const savedSpeed = localStorage.getItem('canSpeed');
@@ -297,7 +297,6 @@ const char index_html[] PROGMEM = R"rawliteral(
document.getElementById('can-speed').value = savedSpeed;
console.log('Restored CAN speed:', speedNames[savedSpeed]);
// 복원되었음을 표시
const statusSpan = document.getElementById('speed-status');
if (statusSpan) {
statusSpan.textContent = '(Restored: ' + speedNames[savedSpeed] + ')';
@@ -423,13 +422,24 @@ const char index_html[] PROGMEM = R"rawliteral(
const msg = canMessages[canId];
let row = existingRows.get(canId);
// 이전 데이터와 비교하여 실제 변경사항 확인
const prevData = lastMessageData[canId];
const hasChanged = !prevData ||
prevData.data !== msg.data ||
prevData.dlc !== msg.dlc ||
prevData.timestamp !== msg.timestamp;
if (row) {
row.cells[1].textContent = msg.dlc;
row.cells[2].textContent = msg.data;
row.cells[3].textContent = msg.updateCount;
row.cells[4].textContent = msg.timestamp;
row.classList.add('flash-row');
setTimeout(() => row.classList.remove('flash-row'), 300);
// 실제로 변경된 경우에만 flash 효과
if (hasChanged) {
row.classList.add('flash-row');
setTimeout(() => row.classList.remove('flash-row'), 300);
}
} else {
row = tbody.insertRow();
row.dataset.canId = canId;
@@ -442,6 +452,14 @@ const char index_html[] PROGMEM = R"rawliteral(
row.classList.add('flash-row');
setTimeout(() => row.classList.remove('flash-row'), 300);
}
// 현재 데이터 저장
lastMessageData[canId] = {
data: msg.data,
dlc: msg.dlc,
timestamp: msg.timestamp,
updateCount: msg.updateCount
};
});
}
@@ -485,10 +503,8 @@ const char index_html[] PROGMEM = R"rawliteral(
ws.send(JSON.stringify({cmd: 'setSpeed', speed: parseInt(speed)}));
// 설정 저장
saveCanSpeed();
// 적용 완료 표시
const statusSpan = document.getElementById('speed-status');
if (statusSpan) {
statusSpan.textContent = ' Applied: ' + speedName;
@@ -511,6 +527,7 @@ const char index_html[] PROGMEM = R"rawliteral(
function clearMessages() {
canMessages = {};
messageOrder = [];
lastMessageData = {};
document.getElementById('can-messages').innerHTML = '';
}
@@ -518,7 +535,6 @@ const char index_html[] PROGMEM = R"rawliteral(
window.location.href = '/download?file=' + encodeURIComponent(filename);
}
// 페이지 로드 시 저장된 CAN speed 복원
window.addEventListener('load', function() {
loadCanSpeed();
});