diff --git a/graph.h b/graph.h
index 2258b34..20de3e0 100644
--- a/graph.h
+++ b/graph.h
@@ -6,7 +6,7 @@ const char graph_html[] PROGMEM = R"rawliteral(
-
π Upload DBC File
+
Upload DBC File
-
ποΈ Click to upload DBC file
-
or drag and drop here
+
Click to upload DBC
+
No file loaded
-
π― Select Signals (Max 6)
+
Select Signals (Max 6)
-
-
-
+
+
+
-
π Real-time Graphs
+
Real-time Graphs
@@ -187,6 +205,32 @@ const char graph_html[] PROGMEM = R"rawliteral(
const MAX_DATA_POINTS = 60;
const COLORS = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40'];
+ // DBC λ°μ΄ν°λ₯Ό localStorageμ μ μ₯
+ function saveDBCToStorage() {
+ try {
+ localStorage.setItem('dbcData', JSON.stringify(dbcData));
+ localStorage.setItem('dbcFileName', document.getElementById('dbc-status').textContent);
+ } catch(e) {
+ console.log('Storage not available');
+ }
+ }
+
+ // μ μ₯λ DBC λ°μ΄ν° λΆλ¬μ€κΈ°
+ function loadDBCFromStorage() {
+ try {
+ const savedDBC = localStorage.getItem('dbcData');
+ const savedFileName = localStorage.getItem('dbcFileName');
+ if (savedDBC && savedFileName && savedFileName !== 'No file loaded') {
+ dbcData = JSON.parse(savedDBC);
+ document.getElementById('dbc-status').textContent = savedFileName;
+ displaySignals();
+ showStatus('DBC file restored: ' + savedFileName, 'success');
+ }
+ } catch(e) {
+ console.log('Could not restore DBC');
+ }
+ }
+
function initWebSocket() {
ws = new WebSocket('ws://' + window.location.hostname + ':81');
@@ -216,6 +260,8 @@ const char graph_html[] PROGMEM = R"rawliteral(
reader.onload = function(e) {
const content = e.target.result;
parseDBCContent(content);
+ document.getElementById('dbc-status').textContent = file.name;
+ saveDBCToStorage();
};
reader.readAsText(file);
}
@@ -228,8 +274,9 @@ const char graph_html[] PROGMEM = R"rawliteral(
for (let line of lines) {
line = line.trim();
+ // BO_ 123 MessageName: 8 Vector__XXX νμ
if (line.startsWith('BO_ ')) {
- const match = line.match(/BO_ (\d+) (\w+):/);
+ const match = line.match(/BO_\s+(\d+)\s+(\w+)\s*:/);
if (match) {
const id = parseInt(match[1]);
const name = match[2];
@@ -237,8 +284,9 @@ const char graph_html[] PROGMEM = R"rawliteral(
dbcData.messages[id] = currentMessage;
}
}
+ // SG_ SignalName : 0|16@1+ (1,0) [0|100] "unit" νμ
else if (line.startsWith('SG_ ') && currentMessage) {
- const match = line.match(/SG_ (\w+) : (\d+)\|(\d+)@([01])([+-]) \(([^,]+),([^)]+)\) \[([^\]]+)\] "([^"]*)"/);
+ const match = line.match(/SG_\s+(\w+)\s*:\s*(\d+)\|(\d+)@([01])([+-])\s*\(([^,]+),([^)]+)\)\s*\[([^\]]+)\]\s*"([^"]*)"/);
if (match) {
const signal = {
name: match[1],
@@ -258,8 +306,7 @@ const char graph_html[] PROGMEM = R"rawliteral(
}
displaySignals();
- showStatus('DBC file loaded successfully! Found ' +
- Object.keys(dbcData.messages).length + ' messages.', 'success');
+ showStatus('DBC loaded: ' + Object.keys(dbcData.messages).length + ' messages', 'success');
}
function displaySignals() {
@@ -276,8 +323,8 @@ const char graph_html[] PROGMEM = R"rawliteral(
'
' + signal.name + '
' +
'
' +
'ID: 0x' + signal.messageId.toString(16).toUpperCase() + ' | ' +
- signal.bitLength + ' bits | ' +
- (signal.unit || 'no unit') +
+ signal.bitLength + 'bit' +
+ (signal.unit ? ' | ' + signal.unit : '') +
'
';
signalList.appendChild(item);
});
@@ -295,7 +342,7 @@ const char graph_html[] PROGMEM = R"rawliteral(
element.classList.remove('selected');
} else {
if (selectedSignals.length >= MAX_SIGNALS) {
- showStatus('Maximum ' + MAX_SIGNALS + ' signals allowed!', 'error');
+ showStatus('Max ' + MAX_SIGNALS + ' signals!', 'error');
return;
}
selectedSignals.push(signal);
@@ -312,18 +359,18 @@ const char graph_html[] PROGMEM = R"rawliteral(
function startGraphing() {
if (selectedSignals.length === 0) {
- showStatus('Please select at least one signal!', 'error');
+ showStatus('Select at least one signal!', 'error');
return;
}
graphing = true;
createGraphs();
- showStatus('Graphing started for ' + selectedSignals.length + ' signals', 'success');
+ showStatus('Graphing ' + selectedSignals.length + ' signals', 'success');
}
function stopGraphing() {
graphing = false;
- showStatus('Graphing stopped', 'success');
+ showStatus('Stopped', 'success');
}
function createGraphs() {
@@ -338,10 +385,11 @@ const char graph_html[] PROGMEM = R"rawliteral(
const canvas = document.createElement('canvas');
canvas.id = 'chart-' + index;
- container.innerHTML = '
' + signal.name +
+ container.innerHTML = '' + signal.name +
' (0x' + signal.messageId.toString(16).toUpperCase() + ')' +
- (signal.unit ? ' [' + signal.unit + ']' : '') + '
';
- container.appendChild(canvas);
+ (signal.unit ? ' [' + signal.unit + ']' : '') + '
' +
+ '
';
+ container.querySelector('.graph-canvas').appendChild(canvas);
graphsDiv.appendChild(container);
const ctx = canvas.getContext('2d');
@@ -362,14 +410,8 @@ const char graph_html[] PROGMEM = R"rawliteral(
responsive: true,
maintainAspectRatio: false,
scales: {
- x: {
- display: true,
- title: { display: true, text: 'Time' }
- },
- y: {
- display: true,
- title: { display: true, text: signal.unit || 'Value' }
- }
+ x: { display: true, title: { display: true, text: 'Time' }},
+ y: { display: true, title: { display: true, text: signal.unit || 'Value' }}
},
animation: false
}
@@ -404,15 +446,17 @@ const char graph_html[] PROGMEM = R"rawliteral(
function decodeSignal(signal, hexData) {
const bytes = [];
- for (let i = 0; i < hexData.length; i += 3) {
- bytes.push(parseInt(hexData.substr(i, 2), 16));
+ const parts = hexData.split(' ');
+ for (let part of parts) {
+ if (part.length === 2) {
+ bytes.push(parseInt(part, 16));
+ }
}
let rawValue = 0;
- const startByte = Math.floor(signal.startBit / 8);
- const startBitInByte = signal.startBit % 8;
if (signal.byteOrder === 'intel') {
+ // Little Endian (Intel)
for (let i = 0; i < signal.bitLength; i++) {
const bitPos = signal.startBit + i;
const byteIdx = Math.floor(bitPos / 8);
@@ -424,18 +468,20 @@ const char graph_html[] PROGMEM = R"rawliteral(
}
}
} else {
+ // Big Endian (Motorola)
for (let i = 0; i < signal.bitLength; i++) {
const bitPos = signal.startBit - i;
const byteIdx = Math.floor(bitPos / 8);
- const bitIdx = bitPos % 8;
+ const bitIdx = 7 - (bitPos % 8);
- if (byteIdx < bytes.length) {
+ if (byteIdx < bytes.length && byteIdx >= 0) {
const bit = (bytes[byteIdx] >> bitIdx) & 1;
rawValue |= (bit << (signal.bitLength - 1 - i));
}
}
}
+ // Signed μ²λ¦¬
if (signal.signed && (rawValue & (1 << (signal.bitLength - 1)))) {
rawValue -= (1 << signal.bitLength);
}
@@ -453,14 +499,12 @@ const char graph_html[] PROGMEM = R"rawliteral(
const uploadArea = document.querySelector('.upload-area');
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
- uploadArea.addEventListener(eventName, preventDefaults, false);
+ uploadArea.addEventListener(eventName, e => {
+ e.preventDefault();
+ e.stopPropagation();
+ });
});
- function preventDefaults(e) {
- e.preventDefault();
- e.stopPropagation();
- }
-
['dragenter', 'dragover'].forEach(eventName => {
uploadArea.addEventListener(eventName, () => {
uploadArea.style.borderColor = '#185a9d';
@@ -481,11 +525,18 @@ const char graph_html[] PROGMEM = R"rawliteral(
const reader = new FileReader();
reader.onload = function(ev) {
parseDBCContent(ev.target.result);
+ document.getElementById('dbc-status').textContent = file.name;
+ saveDBCToStorage();
};
reader.readAsText(file);
}
});
+ // νμ΄μ§ λ‘λ μ μ μ₯λ DBC 볡μ
+ window.addEventListener('load', function() {
+ loadDBCFromStorage();
+ });
+
initWebSocket();