최종 ext ID 수신 확인
This commit is contained in:
@@ -809,7 +809,7 @@ void webUpdateTask(void *pvParameters) {
|
||||
uint32_t lastStatusUpdate = 0;
|
||||
uint32_t lastCanUpdate = 0;
|
||||
uint32_t lastTxStatusUpdate = 0;
|
||||
const uint32_t CAN_UPDATE_INTERVAL = 500;
|
||||
const uint32_t CAN_UPDATE_INTERVAL = 500; // 0.5초마다 전송
|
||||
|
||||
Serial.println("웹 업데이트 태스크 시작");
|
||||
|
||||
@@ -870,11 +870,13 @@ void webUpdateTask(void *pvParameters) {
|
||||
lastStatusUpdate = now;
|
||||
}
|
||||
|
||||
// CAN 메시지 일괄 업데이트
|
||||
// CAN 메시지 일괄 업데이트 - 항상 전송 (데이터가 있으면)
|
||||
if (now - lastCanUpdate >= CAN_UPDATE_INTERVAL) {
|
||||
String canBatch = "{\"type\":\"canBatch\",\"messages\":[";
|
||||
bool first = true;
|
||||
int messageCount = 0;
|
||||
|
||||
// recentData 배열을 순회하면서 유효한 메시지만 전송
|
||||
for (int i = 0; i < RECENT_MSG_COUNT; i++) {
|
||||
if (recentData[i].msg.timestamp_us > 0) {
|
||||
CANMessage* msg = &recentData[i].msg;
|
||||
@@ -900,13 +902,19 @@ void webUpdateTask(void *pvParameters) {
|
||||
uint64_t timestamp_ms = msg->timestamp_us / 1000;
|
||||
canBatch += "\",\"timestamp\":" + String((uint32_t)timestamp_ms);
|
||||
canBatch += ",\"count\":" + String(recentData[i].count) + "}";
|
||||
|
||||
messageCount++;
|
||||
}
|
||||
}
|
||||
|
||||
canBatch += "]}";
|
||||
|
||||
if (!first) {
|
||||
// 메시지가 하나라도 있으면 전송
|
||||
if (messageCount > 0) {
|
||||
webSocket.broadcastTXT(canBatch);
|
||||
|
||||
// 디버깅: 전송된 메시지 수 로그 (필요시)
|
||||
// Serial.printf("WebSocket: Sent %d CAN messages\n", messageCount);
|
||||
}
|
||||
|
||||
lastCanUpdate = now;
|
||||
|
||||
138
graph_viewer.h
138
graph_viewer.h
@@ -416,6 +416,7 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
|
||||
dbcData.messages[sig.messageId].signals.push(sig);
|
||||
});
|
||||
|
||||
console.log('Loaded', selectedSignals.length, 'signals');
|
||||
return true;
|
||||
} catch(e) {
|
||||
console.error('Failed to load data:', e);
|
||||
@@ -482,12 +483,14 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
|
||||
startTime = Date.now();
|
||||
lastTimestamps = {};
|
||||
updateStatus('Graphing...', false);
|
||||
console.log('Started graphing at', new Date().toISOString());
|
||||
}
|
||||
}
|
||||
|
||||
function stopGraphing() {
|
||||
graphing = false;
|
||||
updateStatus('Stopped', false);
|
||||
console.log('Stopped graphing');
|
||||
}
|
||||
|
||||
function setScaleMode(mode) {
|
||||
@@ -516,33 +519,60 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
|
||||
const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(1);
|
||||
const sortedSignals = sortSignalsForDisplay();
|
||||
|
||||
console.log('Processing', messages.length, 'messages at time', elapsedTime + 's');
|
||||
|
||||
let processedCount = 0;
|
||||
|
||||
messages.forEach(canMsg => {
|
||||
const idStr = canMsg.id.replace(/\s/g, '').toUpperCase();
|
||||
const msgId = parseInt(idStr, 16);
|
||||
let msgId = parseInt(idStr, 16);
|
||||
|
||||
// Extended CAN ID 처리 (bit 31 제거)
|
||||
if (msgId & 0x80000000) {
|
||||
msgId = msgId & 0x1FFFFFFF;
|
||||
}
|
||||
|
||||
const timestamp = canMsg.timestamp;
|
||||
|
||||
sortedSignals.forEach((signal, index) => {
|
||||
if (signal.messageId === msgId && charts[index]) {
|
||||
try {
|
||||
const signalKey = msgId + '_' + signal.name;
|
||||
const value = decodeSignal(signal, canMsg.data);
|
||||
|
||||
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 : '');
|
||||
}
|
||||
// 항상 추가 (중복 체크 제거)
|
||||
charts[index].addData(value, elapsedTime);
|
||||
|
||||
const valueDiv = document.getElementById('value-' + index);
|
||||
if (valueDiv) {
|
||||
valueDiv.textContent = value.toFixed(2) + (signal.unit ? ' ' + signal.unit : '');
|
||||
}
|
||||
|
||||
processedCount++;
|
||||
} catch(e) {
|
||||
console.error('Error decoding signal:', e);
|
||||
console.error('Error decoding signal ' + signal.name + ':', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (processedCount > 0) {
|
||||
console.log('Added', processedCount, 'new data points');
|
||||
}
|
||||
|
||||
// 통계 업데이트
|
||||
updateStatistics();
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
let totalDataPoints = 0;
|
||||
Object.values(charts).forEach(chart => {
|
||||
totalDataPoints += chart.data.length;
|
||||
});
|
||||
|
||||
document.getElementById('data-point-count').textContent = totalDataPoints;
|
||||
|
||||
const recordingTime = ((Date.now() - startTime) / 1000).toFixed(1);
|
||||
document.getElementById('recording-time').textContent = recordingTime + 's';
|
||||
}
|
||||
|
||||
function decodeSignal(signal, hexData) {
|
||||
@@ -590,6 +620,88 @@ const char graph_viewer_html[] PROGMEM = R"rawliteral(
|
||||
return rawValue * signal.factor + signal.offset;
|
||||
}
|
||||
|
||||
function downloadCSV() {
|
||||
if (Object.keys(charts).length === 0) {
|
||||
alert('No data to download!');
|
||||
return;
|
||||
}
|
||||
|
||||
let csvContent = 'Time(s)';
|
||||
const sortedSignals = sortSignalsForDisplay();
|
||||
|
||||
// 헤더 생성
|
||||
sortedSignals.forEach(signal => {
|
||||
const unit = signal.unit ? ' [' + signal.unit + ']' : '';
|
||||
csvContent += ',' + signal.name + unit;
|
||||
});
|
||||
csvContent += '\n';
|
||||
|
||||
// 데이터 생성
|
||||
let maxLength = 0;
|
||||
Object.values(charts).forEach(chart => {
|
||||
if (chart.labels.length > maxLength) {
|
||||
maxLength = chart.labels.length;
|
||||
}
|
||||
});
|
||||
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
let row = '';
|
||||
let timeValue = '';
|
||||
|
||||
sortedSignals.forEach((signal, index) => {
|
||||
const chart = charts[index];
|
||||
if (chart && chart.labels[i] !== undefined) {
|
||||
if (timeValue === '') {
|
||||
timeValue = chart.labels[i];
|
||||
}
|
||||
row += ',' + chart.data[i].toFixed(6);
|
||||
} else {
|
||||
row += ',';
|
||||
}
|
||||
});
|
||||
|
||||
if (timeValue !== '') {
|
||||
csvContent += timeValue + row + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const link = document.createElement('a');
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', 'can_signals_' + timestamp + '.csv');
|
||||
link.style.visibility = 'hidden';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('CSV downloaded with ' + maxLength + ' data points');
|
||||
}
|
||||
|
||||
function clearData() {
|
||||
if (!confirm('Clear all recorded data? This cannot be undone.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.values(charts).forEach(chart => {
|
||||
chart.data = [];
|
||||
chart.times = [];
|
||||
chart.labels = [];
|
||||
chart.currentValue = 0;
|
||||
chart.draw();
|
||||
});
|
||||
|
||||
lastTimestamps = {};
|
||||
startTime = Date.now();
|
||||
|
||||
updateStatistics();
|
||||
|
||||
console.log('All data cleared');
|
||||
}
|
||||
|
||||
if (loadData()) {
|
||||
createGraphs();
|
||||
initWebSocket();
|
||||
|
||||
Reference in New Issue
Block a user