리셋 시 세팅저장
This commit is contained in:
@@ -275,6 +275,10 @@ char startLogicOp[4] = "OR";
|
||||
char stopLogicOp[4] = "OR";
|
||||
bool autoTriggerActive = false;
|
||||
bool autoTriggerLogCSV = false; // 🆕 Auto Trigger용 CSV 형식 설정
|
||||
|
||||
// 🆕 File Format 저장 변수
|
||||
bool savedCanLogFormatCSV = false; // 저장된 CAN 로그 형식 (BIN=false, CSV=true)
|
||||
|
||||
volatile bool serialLoggingEnabled = false;
|
||||
volatile bool serial2LoggingEnabled = false; // ⭐ Serial2 추가
|
||||
volatile bool sdCardReady = false;
|
||||
@@ -298,7 +302,7 @@ volatile uint64_t serialLogStartTime = 0;
|
||||
volatile uint64_t serial2LogStartTime = 0; // ⭐ Serial2 추가
|
||||
|
||||
// 기타 전역 변수
|
||||
MCP2515Mode currentMcpMode = MCP_MODE_LISTEN_ONLY;
|
||||
MCP2515Mode currentMcpMode;
|
||||
SoftWire rtcWire(RTC_SDA, RTC_SCL);
|
||||
char rtcSyncBuffer[20];
|
||||
CAN_SPEED currentCanSpeed = CAN_1000KBPS;
|
||||
@@ -348,12 +352,23 @@ void resetMCP2515() {
|
||||
// 4. MCP2515 재초기화
|
||||
mcp2515.reset();
|
||||
delay(100);
|
||||
|
||||
// ✅ Preferences에서 설정 불러오기
|
||||
preferences.begin("can-logger", true);
|
||||
int speedIndex = preferences.getInt("can_speed", 3);
|
||||
if (speedIndex >= 0 && speedIndex < 4) {
|
||||
currentCanSpeed = canSpeedValues[speedIndex];
|
||||
}
|
||||
int savedMode = preferences.getInt("mcp_mode", 1);
|
||||
if (savedMode >= 0 && savedMode <= 3) {
|
||||
currentMcpMode = (MCP2515Mode)savedMode;
|
||||
}
|
||||
preferences.end();
|
||||
|
||||
Serial.printf("🔧 resetMCP2515: Speed=%d, Mode=%d\n", (int)currentCanSpeed, (int)currentMcpMode);
|
||||
|
||||
mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ);
|
||||
delay(10);
|
||||
mcp2515.setListenOnlyMode();
|
||||
//currentMcpMode = MCP_MODE_LISTEN_ONLY;
|
||||
|
||||
|
||||
|
||||
// 5. 모드 설정 (Normal/Loopback/Listen Only)
|
||||
if (currentMcpMode == MCP_MODE_NORMAL) {
|
||||
@@ -639,10 +654,15 @@ void loadSettings() {
|
||||
}
|
||||
|
||||
int savedMode = preferences.getInt("mcp_mode", 1);
|
||||
Serial.printf("📥 loadSettings: MCP Mode = %d\n", savedMode);
|
||||
if (savedMode >= 0 && savedMode <= 3) {
|
||||
currentMcpMode = (MCP2515Mode)savedMode;
|
||||
}
|
||||
|
||||
// 🆕 File Format 불러오기
|
||||
savedCanLogFormatCSV = preferences.getBool("can_format_csv", false);
|
||||
Serial.printf("📥 loadSettings: CAN Format = %s\n", savedCanLogFormatCSV ? "CSV" : "BIN");
|
||||
|
||||
loadSerialSettings();
|
||||
preferences.end();
|
||||
}
|
||||
@@ -833,9 +853,19 @@ void saveAutoTriggerSettings() {
|
||||
|
||||
preferences.putBool("enabled", autoTriggerEnabled);
|
||||
preferences.putBool("logCSV", autoTriggerLogCSV); // 🆕 로그 형식 저장
|
||||
Serial.printf("💾 Save: autoTriggerLogCSV = %d\n", autoTriggerLogCSV);
|
||||
preferences.putString("start_logic", startLogicOp);
|
||||
preferences.putString("stop_logic", stopLogicOp);
|
||||
|
||||
// 디버그: Start Triggers 저장
|
||||
Serial.printf("💾 Save: startTriggerCount = %d\n", startTriggerCount);
|
||||
for (int i = 0; i < startTriggerCount; i++) {
|
||||
Serial.printf(" [%d] ID=0x%X, Bit=%d, Len=%d, Op=%s, Val=%ld, En=%d\n",
|
||||
i, startTriggers[i].canId, startTriggers[i].startBit,
|
||||
startTriggers[i].bitLength, startTriggers[i].op,
|
||||
startTriggers[i].value, startTriggers[i].enabled);
|
||||
}
|
||||
|
||||
preferences.putInt("start_count", startTriggerCount);
|
||||
for (int i = 0; i < startTriggerCount; i++) {
|
||||
char key[32];
|
||||
@@ -884,6 +914,7 @@ void loadAutoTriggerSettings() {
|
||||
|
||||
autoTriggerEnabled = preferences.getBool("enabled", false);
|
||||
autoTriggerLogCSV = preferences.getBool("logCSV", false); // 🆕 로그 형식 로드
|
||||
Serial.printf("📥 Load: autoTriggerLogCSV = %d\n", autoTriggerLogCSV);
|
||||
preferences.getString("start_logic", startLogicOp, sizeof(startLogicOp));
|
||||
preferences.getString("stop_logic", stopLogicOp, sizeof(stopLogicOp));
|
||||
|
||||
@@ -914,6 +945,15 @@ void loadAutoTriggerSettings() {
|
||||
startTriggers[i].enabled = preferences.getBool(key, true);
|
||||
}
|
||||
|
||||
// 디버그: Start Triggers 출력
|
||||
Serial.printf("📥 Load: startTriggerCount = %d\n", startTriggerCount);
|
||||
for (int i = 0; i < startTriggerCount; i++) {
|
||||
Serial.printf(" [%d] ID=0x%X, Bit=%d, Len=%d, Op=%s, Val=%ld, En=%d\n",
|
||||
i, startTriggers[i].canId, startTriggers[i].startBit,
|
||||
startTriggers[i].bitLength, startTriggers[i].op,
|
||||
startTriggers[i].value, startTriggers[i].enabled);
|
||||
}
|
||||
|
||||
stopTriggerCount = preferences.getInt("stop_count", 0);
|
||||
if (stopTriggerCount > MAX_TRIGGERS) stopTriggerCount = MAX_TRIGGERS;
|
||||
|
||||
@@ -960,6 +1000,12 @@ void saveSettings() {
|
||||
}
|
||||
|
||||
preferences.putInt("mcp_mode", (int)currentMcpMode);
|
||||
Serial.printf("💾 MCP Mode 저장: %d\n", (int)currentMcpMode);
|
||||
|
||||
// 🆕 File Format 저장
|
||||
preferences.putBool("can_format_csv", savedCanLogFormatCSV);
|
||||
Serial.printf("💾 CAN Format 저장: %s\n", savedCanLogFormatCSV ? "CSV" : "BIN");
|
||||
|
||||
saveSerialSettings();
|
||||
preferences.end();
|
||||
}
|
||||
@@ -1082,6 +1128,7 @@ void rtcSyncTask(void *parameter) {
|
||||
// MCP2515 모드
|
||||
// ========================================
|
||||
bool setMCP2515Mode(MCP2515Mode mode) {
|
||||
Serial.printf("🔧 MCP Mode 변경 요청: %d → ", (int)mode);
|
||||
const char* modeName;
|
||||
MCP2515::ERROR result;
|
||||
|
||||
@@ -1652,7 +1699,75 @@ void sequenceTask(void *parameter) {
|
||||
// WebSocket 이벤트 처리 (중요!)
|
||||
// ========================================
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
|
||||
if (type == WStype_TEXT) {
|
||||
// 🆕 WebSocket 연결 시 현재 설정 전송
|
||||
if (type == WStype_CONNECTED) {
|
||||
Serial.printf("[%u] ✅ WebSocket 연결됨\n", num);
|
||||
|
||||
// 기본 설정 전송
|
||||
DynamicJsonDocument settings(512);
|
||||
settings["type"] = "currentSettings";
|
||||
|
||||
int speedIndex = 3;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (canSpeedValues[i] == currentCanSpeed) {
|
||||
speedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
settings["canSpeed"] = speedIndex;
|
||||
settings["mcpMode"] = (int)currentMcpMode;
|
||||
settings["autoTriggerEnabled"] = autoTriggerEnabled;
|
||||
settings["autoTriggerLogCSV"] = autoTriggerLogCSV;
|
||||
|
||||
String json;
|
||||
serializeJson(settings, json);
|
||||
webSocket.sendTXT(num, json);
|
||||
|
||||
// Auto Trigger 설정도 전송
|
||||
if (autoTriggerEnabled) {
|
||||
delay(50); // 메시지 간격
|
||||
|
||||
DynamicJsonDocument autoTrigger(2048);
|
||||
autoTrigger["type"] = "autoTriggers";
|
||||
autoTrigger["enabled"] = autoTriggerEnabled;
|
||||
autoTrigger["logFormat"] = autoTriggerLogCSV ? "csv" : "bin";
|
||||
autoTrigger["startLogic"] = startLogicOp;
|
||||
autoTrigger["stopLogic"] = stopLogicOp;
|
||||
autoTrigger["startFormula"] = startFormula;
|
||||
autoTrigger["stopFormula"] = stopFormula;
|
||||
|
||||
JsonArray startArray = autoTrigger.createNestedArray("startTriggers");
|
||||
for (int i = 0; i < startTriggerCount; i++) {
|
||||
JsonObject t = startArray.createNestedObject();
|
||||
char idStr[10];
|
||||
sprintf(idStr, "0x%03X", startTriggers[i].canId);
|
||||
t["canId"] = idStr;
|
||||
t["startBit"] = startTriggers[i].startBit;
|
||||
t["bitLength"] = startTriggers[i].bitLength;
|
||||
t["op"] = startTriggers[i].op;
|
||||
t["value"] = (long)startTriggers[i].value;
|
||||
t["enabled"] = startTriggers[i].enabled;
|
||||
}
|
||||
|
||||
JsonArray stopArray = autoTrigger.createNestedArray("stopTriggers");
|
||||
for (int i = 0; i < stopTriggerCount; i++) {
|
||||
JsonObject t = stopArray.createNestedObject();
|
||||
char idStr[10];
|
||||
sprintf(idStr, "0x%03X", stopTriggers[i].canId);
|
||||
t["canId"] = idStr;
|
||||
t["startBit"] = stopTriggers[i].startBit;
|
||||
t["bitLength"] = stopTriggers[i].bitLength;
|
||||
t["op"] = stopTriggers[i].op;
|
||||
t["value"] = (long)stopTriggers[i].value;
|
||||
t["enabled"] = stopTriggers[i].enabled;
|
||||
}
|
||||
|
||||
String autoJson;
|
||||
serializeJson(autoTrigger, autoJson);
|
||||
webSocket.sendTXT(num, autoJson);
|
||||
}
|
||||
}
|
||||
else if (type == WStype_TEXT) {
|
||||
DynamicJsonDocument doc(44384);
|
||||
DeserializationError error = deserializeJson(doc, payload);
|
||||
|
||||
@@ -2242,6 +2357,23 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
|
||||
serializeJson(response, json);
|
||||
webSocket.sendTXT(num, json);
|
||||
}
|
||||
// 🆕 CAN File Format 저장 명령 (메인 페이지용)
|
||||
else if (strcmp(cmd, "saveCanFormat") == 0) {
|
||||
const char* format = doc["format"];
|
||||
if (format) {
|
||||
savedCanLogFormatCSV = (strcmp(format, "csv") == 0);
|
||||
saveSettings();
|
||||
Serial.printf("💾 CAN File Format 저장: %s\n", savedCanLogFormatCSV ? "CSV" : "BIN");
|
||||
}
|
||||
|
||||
DynamicJsonDocument response(128);
|
||||
response["type"] = "canFormatSaved";
|
||||
response["format"] = savedCanLogFormatCSV ? "csv" : "bin";
|
||||
|
||||
String json;
|
||||
serializeJson(response, json);
|
||||
webSocket.sendTXT(num, json);
|
||||
}
|
||||
else if (strcmp(cmd, "setStartTriggers") == 0) {
|
||||
JsonArray triggers = doc["triggers"];
|
||||
strcpy(startLogicOp, doc["logic"] | "OR");
|
||||
@@ -2698,6 +2830,9 @@ void webUpdateTask(void *parameter) {
|
||||
doc["lowVoltage"] = powerStatus.lowVoltage;
|
||||
doc["mcpMode"] = (int)currentMcpMode;
|
||||
|
||||
// 🆕 저장된 File Format 전송
|
||||
doc["savedCanFormat"] = savedCanLogFormatCSV ? "csv" : "bin";
|
||||
|
||||
if (loggingEnabled && currentFilename[0] != '\0') {
|
||||
doc["currentFile"] = String(currentFilename);
|
||||
} else {
|
||||
@@ -2925,11 +3060,19 @@ void setup() {
|
||||
|
||||
mcp2515.reset();
|
||||
delay(100);
|
||||
// ✅ loadSettings()에서 이미 불러왔으므로 중복 제거
|
||||
mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ);
|
||||
delay(10);
|
||||
Serial.printf("🔧 Setup: MCP Mode = %d\n", (int)currentMcpMode);
|
||||
|
||||
// 5. 모드 설정 (Normal/Loopback/Listen Only)
|
||||
if (currentMcpMode == MCP_MODE_NORMAL) {
|
||||
mcp2515.setNormalMode();
|
||||
} else if (currentMcpMode == MCP_MODE_LOOPBACK) {
|
||||
mcp2515.setLoopbackMode();
|
||||
} else {
|
||||
mcp2515.setListenOnlyMode();
|
||||
//currentMcpMode = MCP_MODE_LISTEN_ONLY;
|
||||
currentMcpMode =(MCP2515Mode)preferences.getInt("mcp_mode", 1);
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
@@ -3139,4 +3282,3 @@ void loop() {
|
||||
lastPrint = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
index.h
48
index.h
@@ -971,6 +971,8 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
<span class="format-info">(Text - Excel Ready)</span>
|
||||
</label>
|
||||
</div>
|
||||
<button onclick="saveFileFormat()" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 8px 16px;">💾 Save</button>
|
||||
<span id="format-save-status" style="color: #11998e; font-size: 0.85em; font-weight: 600;"></span>
|
||||
</div>
|
||||
<div class="control-row">
|
||||
<button onclick="startLogging()" style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);">Start Logging</button>
|
||||
@@ -1153,6 +1155,9 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
let commentingFile = '';
|
||||
// hasInitialSync 제거 - 매번 자동 동기화
|
||||
|
||||
// 🆕 File Format 동기화 플래그
|
||||
window.canFormatSynced = false;
|
||||
|
||||
// 🎯 Auto Trigger 전역 변수
|
||||
let startTriggers = [];
|
||||
let stopTriggers = [];
|
||||
@@ -1236,6 +1241,7 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
document.getElementById('sync-status').textContent = '연결 끊김';
|
||||
document.getElementById('sync-status').style.color = '#f45c43';
|
||||
mcpModeSynced = false; // 🆕 재연결 시 다시 동기화하도록 플래그 리셋
|
||||
window.canFormatSynced = false; // 🆕 File Format도 재동기화
|
||||
setTimeout(initWebSocket, 3000);
|
||||
};
|
||||
|
||||
@@ -1332,6 +1338,15 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
else if (data.type === 'stopTriggersSet') {
|
||||
console.log('✅ Stop triggers saved:', data.count);
|
||||
}
|
||||
// 🆕 File Format 저장 결과 처리
|
||||
else if (data.type === 'canFormatSaved') {
|
||||
console.log('✅ CAN Format saved:', data.format);
|
||||
const statusSpan = document.getElementById('format-save-status');
|
||||
if (statusSpan) {
|
||||
statusSpan.textContent = '✓ Saved: ' + data.format.toUpperCase();
|
||||
setTimeout(() => { statusSpan.textContent = ''; }, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto Trigger 상태 업데이트 (update 메시지에서)
|
||||
if (data.autoTriggerEnabled !== undefined) {
|
||||
@@ -1430,6 +1445,19 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
}
|
||||
}
|
||||
|
||||
// 🆕 저장된 File Format 적용 (최초 접속 시 한 번만)
|
||||
if (data.savedCanFormat && !window.canFormatSynced) {
|
||||
const formatRadios = document.getElementsByName('can-format');
|
||||
for (const radio of formatRadios) {
|
||||
if (radio.value === data.savedCanFormat) {
|
||||
radio.checked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
window.canFormatSynced = true;
|
||||
console.log('✅ Loaded saved CAN format:', data.savedCanFormat);
|
||||
}
|
||||
|
||||
// 현재 파일
|
||||
currentLoggingFile = data.currentFile || '';
|
||||
if (data.currentFile) {
|
||||
@@ -1713,6 +1741,26 @@ const char index_html[] PROGMEM = R"rawliteral(
|
||||
console.log('MCP2515 mode set to:', modeName);
|
||||
}
|
||||
|
||||
// 🆕 File Format 저장 함수
|
||||
function saveFileFormat() {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
let canFormat = 'bin';
|
||||
const formatRadios = document.getElementsByName('can-format');
|
||||
for (const radio of formatRadios) {
|
||||
if (radio.checked) {
|
||||
canFormat = radio.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
cmd: 'saveCanFormat',
|
||||
format: canFormat
|
||||
}));
|
||||
|
||||
console.log('Save CAN format:', canFormat);
|
||||
}
|
||||
}
|
||||
|
||||
function startLogging() {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
|
||||
Reference in New Issue
Block a user