diff --git a/graph.h b/graph.h index 139d3ab..6cfb38b 100644 --- a/graph.h +++ b/graph.h @@ -375,11 +375,41 @@ const char graph_html[] PROGMEM = R"rawliteral( } function parseDBCContent(content) { - dbcData = {messages: {}}; + dbcData = {messages: {}, valueTables: {}}; allSignals = []; const lines = content.split('\n'); let currentMessage = null; + // 먼저 VAL_ 정의를 파싱 + for (let line of lines) { + line = line.trim(); + + if (line.startsWith('VAL_ ')) { + // VAL_ 형식: VAL_ "" ...; + const match = line.match(/VAL_\s+(\d+)\s+(\w+)\s+(.+);/); + if (match) { + const msgId = parseInt(match[1]); + const sigName = match[2]; + const valuesStr = match[3]; + + // Extended CAN ID 처리 + const normalizedMsgId = (msgId & 0x80000000) ? (msgId & 0x1FFFFFFF) : msgId; + + const key = normalizedMsgId + '_' + sigName; + dbcData.valueTables[key] = {}; + + // 값-텍스트 쌍 파싱 + const valueMatches = valuesStr.matchAll(/(\d+)\s+"([^"]+)"/g); + for (let vm of valueMatches) { + dbcData.valueTables[key][parseInt(vm[1])] = vm[2]; + } + + console.log('Parsed Value Table: ' + key, dbcData.valueTables[key]); + } + } + } + + // 메시지와 시그널 파싱 for (let line of lines) { line = line.trim(); @@ -390,10 +420,8 @@ const char graph_html[] PROGMEM = R"rawliteral( const name = match[2]; const dlc = parseInt(match[3]); - // Extended CAN ID 처리 (bit 31이 set되어 있으면 제거) - // CAN Extended format에서 bit 31은 Extended ID 플래그 if (id & 0x80000000) { - id = id & 0x1FFFFFFF; // bit 31 제거, 29-bit ID만 사용 + id = id & 0x1FFFFFFF; } currentMessage = { @@ -410,8 +438,9 @@ const char graph_html[] PROGMEM = R"rawliteral( else if (line.startsWith('SG_ ') && currentMessage) { const match = line.match(/SG_\s+(\w+)\s*:\s*(\d+)\|(\d+)@([01])([+-])\s*\(([^,]+),([^)]+)\)\s*\[([^\]]+)\]\s*"([^"]*)"/); if (match) { + const signalName = match[1]; const signal = { - name: match[1], + name: signalName, startBit: parseInt(match[2]), bitLength: parseInt(match[3]), byteOrder: match[4] === '0' ? 'motorola' : 'intel', @@ -424,6 +453,14 @@ const char graph_html[] PROGMEM = R"rawliteral( messageName: currentMessage.name, messageDlc: currentMessage.dlc }; + + // Value Table 연결 + const vtKey = currentMessage.id + '_' + signalName; + if (dbcData.valueTables[vtKey]) { + signal.valueTable = dbcData.valueTables[vtKey]; + console.log(' Signal with value table: ' + signalName, signal.valueTable); + } + currentMessage.signals.push(signal); allSignals.push(signal); @@ -672,7 +709,14 @@ const char graph_html[] PROGMEM = R"rawliteral( console.log('=== DBC Debug Info ==='); console.log('Total Messages: ' + Object.keys(dbcData.messages).length); console.log('Total Signals: ' + allSignals.length); + console.log('Total Value Tables: ' + Object.keys(dbcData.valueTables).length); + console.log('\n=== Value Tables ==='); + for (let key in dbcData.valueTables) { + console.log(key + ':', dbcData.valueTables[key]); + } + + console.log('\n=== Messages ==='); Object.values(dbcData.messages).forEach(msg => { console.log('\nMessage: ' + msg.name); console.log(' ID: ' + msg.id + ' (0x' + msg.id.toString(16).toUpperCase() + ')'); @@ -681,6 +725,9 @@ const char graph_html[] PROGMEM = R"rawliteral( msg.signals.forEach(sig => { console.log(' - ' + sig.name + ': ' + sig.startBit + '|' + sig.bitLength + ' [' + sig.unit + ']'); + if (sig.valueTable) { + console.log(' Value Table:', sig.valueTable); + } }); }); diff --git a/graph_viewer.h b/graph_viewer.h index 86c46d3..aac6462 100644 --- a/graph_viewer.h +++ b/graph_viewer.h @@ -211,8 +211,10 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( this.data = []; this.times = []; this.labels = []; + this.rawValues = []; // 원본 숫자값 저장 this.colors = COLORS[colorIndex % COLORS.length]; this.currentValue = 0; + this.currentText = ''; // 현재 텍스트 값 this.resizeCanvas(); window.addEventListener('resize', () => this.resizeCanvas()); @@ -232,17 +234,33 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( this.data.push(value); this.times.push(parseFloat(time)); this.labels.push(time); + this.rawValues.push(value); this.currentValue = value; + // Value Table이 있으면 텍스트 값 저장 + if (this.signal.valueTable && this.signal.valueTable[value] !== undefined) { + this.currentText = this.signal.valueTable[value]; + } else { + this.currentText = ''; + } + if (scaleMode === 'index' && this.data.length > MAX_DATA_POINTS) { this.data.shift(); this.times.shift(); this.labels.shift(); + this.rawValues.shift(); } this.draw(); } + getValueText(value) { + if (this.signal.valueTable && this.signal.valueTable[value] !== undefined) { + return this.signal.valueTable[value]; + } + return value.toFixed(2); + } + draw() { if (this.data.length === 0) return; @@ -285,6 +303,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( timeRange = maxTime - minTime || 1; } + // 축 그리기 ctx.strokeStyle = '#444'; ctx.lineWidth = 1; ctx.beginPath(); @@ -293,12 +312,31 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( ctx.lineTo(this.width - padding, this.height - padding); ctx.stroke(); + // Y축 레이블 (Value Table이 있으면 텍스트로 표시) 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); + if (this.signal.valueTable) { + // Value Table이 있는 경우 + const uniqueValues = [...new Set(displayData)].sort((a, b) => a - b); + if (uniqueValues.length <= 5) { + uniqueValues.forEach((val, idx) => { + const y = this.height - padding - ((val - minValue) / range) * graphHeight; + const text = this.getValueText(val); + ctx.fillText(text, padding - 5, y + 5); + }); + } else { + ctx.fillText(this.getValueText(maxValue), padding - 5, padding + 5); + ctx.fillText(this.getValueText(minValue), padding - 5, this.height - padding); + } + } else { + // 일반 숫자 표시 + ctx.fillText(maxValue.toFixed(2), padding - 5, padding + 5); + ctx.fillText(minValue.toFixed(2), padding - 5, this.height - padding); + } + + // X축 레이블 ctx.textAlign = 'center'; ctx.fillStyle = '#aaa'; ctx.font = '10px Arial'; @@ -317,6 +355,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( } ctx.fillText('Time (sec)', this.width / 2, this.height - 5); + // 그리드 라인 ctx.strokeStyle = '#333'; ctx.lineWidth = 1; for (let i = 1; i < 5; i++) { @@ -327,6 +366,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( ctx.stroke(); } + // 데이터 포인트 그리기 if (displayData.length < 1) return; ctx.fillStyle = this.colors.line; @@ -417,6 +457,14 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( }); console.log('Loaded', selectedSignals.length, 'signals'); + + // Value Table 정보 로깅 + selectedSignals.forEach(sig => { + if (sig.valueTable) { + console.log('Signal with Value Table:', sig.name, sig.valueTable); + } + }); + return true; } catch(e) { console.error('Failed to load data:', e); @@ -539,12 +587,17 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( try { const value = decodeSignal(signal, canMsg.data); - // 항상 추가 (중복 체크 제거) + // 항상 추가 charts[index].addData(value, elapsedTime); const valueDiv = document.getElementById('value-' + index); if (valueDiv) { - valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : ''); + // Value Table이 있으면 텍스트로 표시 + if (signal.valueTable && signal.valueTable[value] !== undefined) { + valueDiv.textContent = signal.valueTable[value]; + } else { + valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : ''); + } } processedCount++; @@ -633,6 +686,11 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( sortedSignals.forEach(signal => { const unit = signal.unit ? ' [' + signal.unit + ']' : ''; csvContent += ',' + signal.name + unit; + + // Value Table이 있으면 텍스트 컬럼도 추가 + if (signal.valueTable) { + csvContent += ',' + signal.name + '_Text'; + } }); csvContent += '\n'; @@ -654,9 +712,20 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( if (timeValue === '') { timeValue = chart.labels[i]; } - row += ',' + chart.data[i].toFixed(6); + const value = chart.data[i]; + row += ',' + value.toFixed(6); + + // Value Table이 있으면 텍스트도 추가 + if (signal.valueTable) { + const text = signal.valueTable[value] !== undefined ? + signal.valueTable[value] : ''; + row += ',"' + text + '"'; + } } else { row += ','; + if (signal.valueTable) { + row += ','; + } } }); @@ -690,7 +759,9 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral( chart.data = []; chart.times = []; chart.labels = []; + chart.rawValues = []; chart.currentValue = 0; + chart.currentText = ''; chart.draw(); });