00001 에러코드 수정

Z:\byun_work\01.codings\250928_esp32_spi_sdcard_ads8688_mcp\03.wifi_can\ESP32_CAN_Logger\ESP32_CAN_Logger.ino: In function 'void canRxTask(void*)':
Z:\byun_work\01.codings\250928_esp32_spi_sdcard_ads8688_mcp\03.wifi_can\ESP32_CAN_Logger\ESP32_CAN_Logger.ino:261:13: error: 'recentMessages' was not declared in this scope
  261 |             recentMessages[recentMsgIndex] = msg;
      |             ^~~~~~~~~~~~~~
Z:\byun_work\01.codings\250928_esp32_spi_sdcard_ads8688_mcp\03.wifi_can\ESP32_CAN_Logger\ESP32_CAN_Logger.ino:261:28: error: 'recentMsgIndex' was not declared in this scope; did you mean 'recentDataIndex'?
  261 |             recentMessages[recentMsgIndex] = msg;
      |                            ^~~~~~~~~~~~~~
      |                            recentDataIndex
Z:\byun_work\01.codings\250928_esp32_spi_sdcard_ads8688_mcp\03.wifi_can\ESP32_CAN_Logger\ESP32_CAN_Logger.ino: In function 'void webUpdateTask(void*)':
Z:\byun_work\01.codings\250928_esp32_spi_sdcard_ads8688_mcp\03.wifi_can\ESP32_CAN_Logger\ESP32_CAN_Logger.ino:491:21: error: 'recentMessages' was not declared in this scope
  491 |                 if (recentMessages[i].timestamp > 0) {
      |                     ^~~~~~~~~~~~~~
"mcp2515.h"를 위한 복수개의 라이브러리가 발견되었습니다
  사용됨: C:\Users\sinla\OneDrive\문서\Arduino\libraries\autowp-mcp2515
  사용되지 않음: C:\Users\sinla\OneDrive\문서\Arduino\libraries\esp32-mcp2515-master
"SD.h"를 위한 복수개의 라이브러리가 발견되었습니다
  사용됨: C:\Users\sinla\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.0\libraries\SD
  사용되지 않음: C:\Users\sinla\AppData\Local\Arduino15\libraries\SD
exit status 1

Compilation error: 'recentMessages' was not declared in this scope
This commit is contained in:
2025-10-04 17:26:09 +00:00
parent bd2986ae0a
commit 4f0588c7d8

View File

@@ -8,6 +8,8 @@
* - CAN speed adjustment (125K - 1M)
* - Log file download
* - Batch update every 0.5s for real-time performance
* - Accurate message count per CAN ID
* - Current logging file display
*
* Hardware:
* - ESP32 WROVER Module (ESP32-WROOM-32D)
@@ -20,9 +22,6 @@
* Required Libraries:
* - WebSockets by Markus Sattler
* - mcp2515 by autowp
*
* Author: ESP32 CAN Logger Project
* Version: 1.0
*/
#include <Arduino.h>
@@ -36,9 +35,9 @@
#include <freertos/task.h>
#include <freertos/queue.h>
#include <freertos/semphr.h>
#include "index.h" // HTML 페이지
#include "index.h"
// ==================== GPIO 핀 정의 ====================
// GPIO 핀 정의
#define CAN_INT_PIN 27
#define LOGGING_CONTROL_PIN 17
#define LOGGING_STATUS_LED 16
@@ -56,13 +55,13 @@
#define VSPI_SCLK 18
#define VSPI_CS 5
// ==================== 버퍼 설정 ====================
// 버퍼 설정
#define CAN_QUEUE_SIZE 1000
#define FILE_BUFFER_SIZE 8192
#define MAX_FILENAME_LEN 32
#define WEB_UPDATE_INTERVAL 100
#define RECENT_MSG_COUNT 100
// ==================== CAN 메시지 구조체 ====================
// CAN 메시지 구조체
struct CANMessage {
uint32_t timestamp;
uint32_t id;
@@ -70,11 +69,17 @@ struct CANMessage {
uint8_t data[8];
} __attribute__((packed));
// ==================== WiFi AP 설정 ====================
// 실시간 모니터링용 구조체
struct RecentCANData {
CANMessage msg;
uint32_t count;
};
// WiFi AP 설정
const char* ssid = "ESP32_CAN_Logger";
const char* password = "12345678";
// ==================== 전역 변수 ====================
// 전역 변수
SPIClass hspi(HSPI);
SPIClass vspi(VSPI);
MCP2515 mcp2515(HSPI_CS, 10000000, &hspi);
@@ -103,19 +108,13 @@ const char* canSpeedNames[] = {"125K", "250K", "500K", "1M"};
CAN_SPEED canSpeedValues[] = {CAN_125KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS};
// 실시간 모니터링용
#define RECENT_MSG_COUNT 100
struct RecentCANData {
CANMessage msg;
uint32_t count; // 실제 수신 횟수
} recentData[RECENT_MSG_COUNT];
int recentDataIndex = 0;
RecentCANData recentData[RECENT_MSG_COUNT];
uint32_t totalMsgCount = 0;
uint32_t msgPerSecond = 0;
uint32_t lastMsgCountTime = 0;
uint32_t lastMsgCount = 0;
// ==================== CAN 인터럽트 핸들러 ====================
// CAN 인터럽트 핸들러
void IRAM_ATTR canISR() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (canRxTaskHandle != NULL) {
@@ -124,7 +123,7 @@ void IRAM_ATTR canISR() {
}
}
// ==================== CAN 속도 변경 ====================
// CAN 속도 변경
void changeCanSpeed(CAN_SPEED newSpeed) {
detachInterrupt(digitalPinToInterrupt(CAN_INT_PIN));
mcp2515.reset();
@@ -135,7 +134,7 @@ void changeCanSpeed(CAN_SPEED newSpeed) {
Serial.printf("CAN 속도 변경: %s\n", canSpeedNames[newSpeed]);
}
// ==================== 기존 파일 번호 스캔 ====================
// 기존 파일 번호 스캔
void scanExistingFiles() {
if (!sdCardReady) {
fileCounter = 0;
@@ -159,10 +158,8 @@ void scanExistingFiles() {
String name = file.name();
if (name.startsWith("/")) name = name.substring(1);
// canlog_XXXXX.bin 형식 확인
if (name.startsWith("canlog_") && (name.endsWith(".bin") || name.endsWith(".BIN"))) {
// 숫자 부분 추출 (canlog_00005.bin -> 5)
int startIdx = 7; // "canlog_" 길이
int startIdx = 7;
int endIdx = name.lastIndexOf('.');
if (endIdx > startIdx) {
@@ -190,6 +187,8 @@ void scanExistingFiles() {
Serial.println("기존 파일 없음 - 파일 카운터 0으로 시작");
}
}
// 새 로그 파일 생성
bool createNewLogFile() {
if (logFile) {
logFile.flush();
@@ -212,7 +211,7 @@ bool createNewLogFile() {
return true;
}
// ==================== 버퍼 플러시 ====================
// 버퍼 플러시
bool flushBuffer() {
if (bufferIndex == 0) return true;
@@ -234,7 +233,7 @@ bool flushBuffer() {
return false;
}
// ==================== CAN 수신 태스크 ====================
// CAN 수신 태스크
void canRxTask(void *pvParameters) {
struct can_frame frame;
CANMessage msg;
@@ -258,14 +257,43 @@ void canRxTask(void *pvParameters) {
}
}
recentMessages[recentMsgIndex] = msg;
recentMsgIndex = (recentMsgIndex + 1) % RECENT_MSG_COUNT;
// 최근 메시지 저장 및 카운트 증가
bool found = false;
for (int i = 0; i < RECENT_MSG_COUNT; i++) {
if (recentData[i].msg.id == msg.id && recentData[i].msg.timestamp > 0) {
recentData[i].msg = msg;
recentData[i].count++;
found = true;
break;
}
}
if (!found) {
// 새 ID - 빈 슬롯 찾기
for (int i = 0; i < RECENT_MSG_COUNT; i++) {
if (recentData[i].msg.timestamp == 0) {
recentData[i].msg = msg;
recentData[i].count = 1;
found = true;
break;
}
}
// 빈 슬롯 없으면 가장 오래된 것 교체
if (!found) {
static int replaceIndex = 0;
recentData[replaceIndex].msg = msg;
recentData[replaceIndex].count = 1;
replaceIndex = (replaceIndex + 1) % RECENT_MSG_COUNT;
}
}
totalMsgCount++;
}
}
}
// ==================== SD 쓰기 태스크 ====================
// SD 쓰기 태스크
void sdWriteTask(void *pvParameters) {
CANMessage msg;
@@ -295,7 +323,7 @@ void sdWriteTask(void *pvParameters) {
}
}
// ==================== 제어 태스크 ====================
// 제어 태스크
void controlTask(void *pvParameters) {
bool lastLoggingState = false;
@@ -338,7 +366,7 @@ void controlTask(void *pvParameters) {
}
}
// ==================== SD 모니터 태스크 ====================
// SD 모니터 태스크
void sdMonitorTask(void *pvParameters) {
Serial.println("SD 모니터 태스크 시작");
@@ -351,7 +379,6 @@ void sdMonitorTask(void *pvParameters) {
if (sdCardReady) {
Serial.println("SD 카드 준비됨");
// SD 카드가 새로 삽입되면 파일 번호 다시 스캔
scanExistingFiles();
} else {
Serial.println("SD 카드 없음");
@@ -366,45 +393,7 @@ void sdMonitorTask(void *pvParameters) {
}
}
// ==================== 웹소켓 이벤트 핸들러 ====================
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("WebSocket 클라이언트 #%u 연결 해제\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("WebSocket 클라이언트 #%u 연결: %d.%d.%d.%d\n",
num, ip[0], ip[1], ip[2], ip[3]);
// 연결 시 즉시 파일 목록 전송
sendFileList(num);
}
break;
case WStype_TEXT:
{
String msg = String((char*)payload);
if (msg.indexOf("\"cmd\":\"setSpeed\"") >= 0) {
int speedIdx = msg.indexOf("\"speed\":") + 8;
int speed = msg.substring(speedIdx, speedIdx + 1).toInt();
if (speed >= 0 && speed < 4) {
changeCanSpeed(canSpeedValues[speed]);
}
} else if (msg.indexOf("\"cmd\":\"getFiles\"") >= 0) {
// 파일 목록 전송
sendFileList(num);
}
}
break;
}
}
// ==================== 파일 목록 전송 함수 ====================
// 파일 목록 전송
void sendFileList(uint8_t clientNum) {
String fileList = "{\"type\":\"files\",\"files\":[";
@@ -450,11 +439,46 @@ void sendFileList(uint8_t clientNum) {
Serial.printf("파일 목록 전송 완료: %d개 파일\n", fileCount);
}
// ==================== 웹 업데이트 태스크 (0.5초 일괄 전송) ====================
// 웹소켓 이벤트 핸들러
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("WebSocket 클라이언트 #%u 연결 해제\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
Serial.printf("WebSocket 클라이언트 #%u 연결: %d.%d.%d.%d\n",
num, ip[0], ip[1], ip[2], ip[3]);
sendFileList(num);
}
break;
case WStype_TEXT:
{
String msg = String((char*)payload);
if (msg.indexOf("\"cmd\":\"setSpeed\"") >= 0) {
int speedIdx = msg.indexOf("\"speed\":") + 8;
int speed = msg.substring(speedIdx, speedIdx + 1).toInt();
if (speed >= 0 && speed < 4) {
changeCanSpeed(canSpeedValues[speed]);
}
} else if (msg.indexOf("\"cmd\":\"getFiles\"") >= 0) {
sendFileList(num);
}
}
break;
}
}
// 웹 업데이트 태스크
void webUpdateTask(void *pvParameters) {
uint32_t lastStatusUpdate = 0;
uint32_t lastCanUpdate = 0;
const uint32_t CAN_UPDATE_INTERVAL = 500; // 0.5초마다 CAN 데이터 전송
const uint32_t CAN_UPDATE_INTERVAL = 500;
Serial.println("웹 업데이트 태스크 시작");
@@ -475,7 +499,14 @@ void webUpdateTask(void *pvParameters) {
status += "\"logging\":" + String(loggingEnabled ? "true" : "false") + ",";
status += "\"sdReady\":" + String(sdCardReady ? "true" : "false") + ",";
status += "\"msgCount\":" + String(totalMsgCount) + ",";
status += "\"msgSpeed\":" + String(msgPerSecond) + "}";
status += "\"msgSpeed\":" + String(msgPerSecond) + ",";
if (loggingEnabled && logFile) {
status += "\"currentFile\":\"" + String(currentFilename) + "\"";
} else {
status += "\"currentFile\":\"\"";
}
status += "}";
webSocket.broadcastTXT(status);
lastStatusUpdate = now;
@@ -486,10 +517,9 @@ void webUpdateTask(void *pvParameters) {
String canBatch = "{\"type\":\"canBatch\",\"messages\":[";
bool first = true;
// 모든 최근 메시지를 JSON 배열로 구성
for (int i = 0; i < RECENT_MSG_COUNT; i++) {
if (recentMessages[i].timestamp > 0) {
CANMessage* msg = &recentMessages[i];
if (recentData[i].msg.timestamp > 0) {
CANMessage* msg = &recentData[i].msg;
if (!first) canBatch += ",";
first = false;
@@ -508,13 +538,14 @@ void webUpdateTask(void *pvParameters) {
if (j < msg->dlc - 1) canBatch += " ";
}
canBatch += "\",\"timestamp\":" + String(msg->timestamp) + "}";
canBatch += "\",\"timestamp\":" + String(msg->timestamp);
canBatch += ",\"count\":" + String(recentData[i].count) + "}";
}
}
canBatch += "]}";
if (!first) { // 메시지가 있을 때만 전송
if (!first) {
webSocket.broadcastTXT(canBatch);
}
@@ -525,16 +556,16 @@ void webUpdateTask(void *pvParameters) {
}
}
// ==================== SETUP ====================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\n\n");
Serial.println("========================================");
Serial.println("\n\n========================================");
Serial.println(" ESP32 CAN Logger with Web Interface ");
Serial.println("========================================");
// GPIO 초기화
// 배열 초기화
memset(recentData, 0, sizeof(recentData));
pinMode(LOGGING_CONTROL_PIN, INPUT);
pinMode(LOGGING_STATUS_LED, OUTPUT);
pinMode(SD_READY_LED, OUTPUT);
@@ -543,46 +574,37 @@ void setup() {
digitalWrite(LOGGING_STATUS_LED, LOW);
digitalWrite(SD_READY_LED, LOW);
// SPI 초기화
hspi.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_CS);
// MCP2515 초기화
mcp2515.reset();
mcp2515.setBitrate(CAN_1000KBPS, MCP_8MHZ);
mcp2515.setNormalMode();
Serial.println("✓ MCP2515 초기화 완료 (1Mbps)");
// SD 카드 초기화
if (SD.begin(VSPI_CS, vspi)) {
sdCardReady = true;
digitalWrite(SD_READY_LED, HIGH);
Serial.println("✓ SD 카드 초기화 완료");
// 기존 파일 번호 스캔
scanExistingFiles();
} else {
Serial.println("✗ SD 카드 초기화 실패");
fileCounter = 0;
}
// WiFi AP 시작
Serial.println("\nWiFi AP 시작...");
WiFi.softAP(ssid, password);
Serial.print("✓ AP IP 주소: ");
Serial.println(WiFi.softAPIP());
// 웹소켓 설정
webSocket.begin();
webSocket.onEvent(webSocketEvent);
Serial.println("✓ WebSocket 서버 시작 (포트 81)");
// HTTP 핸들러
server.on("/", HTTP_GET, []() {
server.send_P(200, "text/html", index_html);
});
// 파일 다운로드 핸들러
server.on("/download", HTTP_GET, []() {
if (server.hasArg("file")) {
String filename = "/" + server.arg("file");
@@ -606,7 +628,6 @@ void setup() {
server.begin();
Serial.println("✓ 웹 서버 시작 (포트 80)");
// RTOS 객체 생성
canQueue = xQueueCreate(CAN_QUEUE_SIZE, sizeof(CANMessage));
sdMutex = xSemaphoreCreateMutex();
@@ -616,10 +637,8 @@ void setup() {
}
Serial.println("✓ RTOS 객체 생성 완료");
// 인터럽트 설정
attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING);
// 태스크 생성
xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 4096, NULL, 4, &canRxTaskHandle, 1);
xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 12288, NULL, 3, &sdWriteTaskHandle, 1);
xTaskCreatePinnedToCore(controlTask, "CONTROL", 8192, NULL, 2, &controlTaskHandle, 0);
@@ -627,41 +646,26 @@ void setup() {
xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 8192, NULL, 2, &webTaskHandle, 0);
Serial.println("✓ 모든 RTOS 태스크 시작 완료");
Serial.println("\n========================================");
Serial.println(" GPIO 핀 설정");
Serial.println(" 웹 인터페이스 접속");
Serial.println("========================================");
Serial.println(" GPIO17: 로깅 제어 (HIGH=시작, LOW=정지)");
Serial.println(" GPIO16: 로깅 상태 LED");
Serial.println(" GPIO26: SD 카드 준비 LED");
Serial.println(" GPIO27: CAN 인터럽트");
Serial.println("\n========================================");
Serial.println(" 웹 인터페이스 접속 방법");
Serial.println("========================================");
Serial.println(" 1. WiFi 연결: ESP32_CAN_Logger");
Serial.println(" 2. 비밀번호: 12345678");
Serial.print(" 3. 브라우저: http://");
Serial.println(" 1. WiFi: ESP32_CAN_Logger (12345678)");
Serial.print(" 2. http://");
Serial.println(WiFi.softAPIP());
Serial.println("========================================\n");
}
// ==================== LOOP ====================
void loop() {
server.handleClient();
vTaskDelay(pdMS_TO_TICKS(10));
// 디버그 정보 (10초마다)
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 10000) {
Serial.printf("[상태] 큐: %d/%d | 로깅: %s | SD: %s | 총: %lu msg | 속도: %lu msg/s\n",
uxQueueMessagesWaiting(canQueue),
CAN_QUEUE_SIZE,
Serial.printf("[상태] 큐: %d/%d | 로깅: %s | SD: %s | 총: %lu | 속도: %lu msg/s\n",
uxQueueMessagesWaiting(canQueue), CAN_QUEUE_SIZE,
loggingEnabled ? "ON " : "OFF",
sdCardReady ? "Ready " : "Not Ready",
totalMsgCount,
msgPerSecond
);
sdCardReady ? "Ready" : "No ",
totalMsgCount, msgPerSecond);
lastPrint = millis();
}
}