diff --git a/ESP32_SerialLogger.ino b/ESP32_SerialLogger.ino new file mode 100644 index 0000000..4ecfa32 --- /dev/null +++ b/ESP32_SerialLogger.ino @@ -0,0 +1,190 @@ +// ============================================================ +// ESP32 Serial Logger +// Hardware: ESP-WROOM-32D DevKitC V4 +// +// Arduino IDE Settings: +// Board: "ESP32 Dev Module" +// Upload Speed: 921600 +// CPU Frequency: 240MHz (WiFi/BT) +// Flash Frequency: 80MHz +// Flash Mode: QIO +// Flash Size: 4MB (32Mb) +// Partition Scheme: "Huge APP (3MB No OTA/1MB SPIFFS)" +// PSRAM: Disabled +// +// Required Libraries: +// 1. WebSocketsServer by Links2004 +// (Install: Library Manager -> "WebSockets" by Markus Sattler) +// 2. ArduinoJson by Benoit Blanchon v6.x +// (Install: Library Manager -> "ArduinoJson") +// 3. SD (built-in) +// 4. SPI (built-in) +// +// Pin Assignments: +// UART2 TX: GPIO17 | UART2 RX: GPIO16 +// SD CLK: GPIO14 | SD MISO: GPIO26 | SD MOSI: GPIO13 | SD CS: GPIO15 +// ============================================================ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "serial_task.h" +#include "sdcard_task.h" +#include "web_task.h" + +// ============================================================ +// NTP Time Sync Task +// Only works in STA mode (internet required) +// In AP mode, time is synced from browser via WebSocket +// ============================================================ +void ntpSyncTask(void *param) { + Serial.println("[Task] NTP Sync started"); + + // Only attempt NTP if connected to external WiFi (STA mode) + if (WiFi.getMode() == WIFI_AP) { + Serial.println("[NTP] AP mode - skipping NTP, waiting for browser time sync"); + // In AP mode, just keep task alive for potential future use + while (true) { + vTaskDelay(pdMS_TO_TICKS(60000)); + } + } + + // STA mode - try NTP + configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER); + + struct tm timeinfo; + int retries = 0; + while (!getLocalTime(&timeinfo) && retries < 5) { + Serial.println("[NTP] Waiting for time sync..."); + vTaskDelay(pdMS_TO_TICKS(1000)); + retries++; + } + + if (getLocalTime(&timeinfo)) { + Serial.printf("[NTP] Synced: %04d-%02d-%02d %02d:%02d:%02d\n", + timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, + timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec); + } else { + Serial.println("[NTP] Failed - will use browser time when client connects"); + } + + // Periodic re-sync every 1 hour + while (true) { + vTaskDelay(pdMS_TO_TICKS(3600000)); + configTime(NTP_GMT_OFFSET, NTP_DAYLIGHT_OFFSET, NTP_SERVER); + Serial.println("[NTP] Time re-synced"); + } +} + +// ============================================================ +// WiFi Connection (STA + fallback AP mode) +// ============================================================ +void wifiConnect() { + Serial.println("[WiFi] Connecting to: " + String(WIFI_SSID)); + + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + WiFi.setSleep(false); + + unsigned long startTime = millis(); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + if (millis() - startTime > WIFI_CONNECT_TIMEOUT) { + Serial.println("\n[WiFi] STA failed! Starting AP mode..."); + WiFi.mode(WIFI_AP); + WiFi.softAP(WIFI_AP_SSID, WIFI_AP_PASSWORD); + Serial.println("[WiFi] AP SSID: " + String(WIFI_AP_SSID)); + Serial.println("[WiFi] AP IP: " + WiFi.softAPIP().toString()); + return; + } + } + + Serial.println(); + Serial.println("[WiFi] Connected! IP: " + WiFi.localIP().toString()); + Serial.println("[WiFi] RSSI: " + String(WiFi.RSSI()) + " dBm"); +} + +// ============================================================ +// Setup +// ============================================================ +void setup() { + Serial.begin(115200); + delay(1000); + + Serial.println("============================================"); + Serial.println(" ESP32 Serial Logger v1.0"); + Serial.println(" ESP-WROOM-32D DevKitC V4"); + Serial.println("============================================"); + Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap()); + Serial.printf(" CPU Freq: %d MHz\n", getCpuFrequencyMhz()); + Serial.println("============================================"); + + // 1. WiFi + wifiConnect(); + + // 2. NTP (STA mode only) + Browser time sync (AP mode) + xTaskCreatePinnedToCore(ntpSyncTask, "NTP", TASK_STACK_NTP, + NULL, TASK_PRIORITY_NTP, NULL, 0); + if (WiFi.getMode() != WIFI_AP) { + delay(2000); // Brief wait for NTP only in STA mode + } else { + Serial.println("[Time] AP mode: time will sync from browser on first connect"); + } + + // 3. SD Card + sdTaskInit(); + + // 4. Serial2 UART + serialTaskInit(); + + // 5. Web Server + WebSocket + webTaskInit(); + + Serial.println("============================================"); + Serial.println(" All tasks started!"); + Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap()); + + String ip = (WiFi.getMode() == WIFI_AP) ? + WiFi.softAPIP().toString() : WiFi.localIP().toString(); + Serial.println(" URL: http://" + ip); + Serial.println("============================================"); + Serial.println("\n Task Layout:"); + Serial.println(" Core 1: SerialRX(5), SerialTX(4)"); + Serial.println(" Core 0: SDLog(3), WebBC(2), NTP(1)"); + Serial.println(" Loop : server.handleClient()"); + Serial.println(" Time : NTP(STA) or Browser sync(AP)"); + Serial.println("============================================\n"); +} + +// ============================================================ +// Loop - handles HTTP requests (must be on main loop) +// ============================================================ +void loop() { + server.handleClient(); + vTaskDelay(pdMS_TO_TICKS(2)); + + // Periodic status report (30s) + static unsigned long lastReport = 0; + if (millis() - lastReport > 30000) { + lastReport = millis(); + Serial.printf("[SYS] Heap: %d | MinHeap: %d | SD: %s | WS: %d clients\n", + ESP.getFreeHeap(), + ESP.getMinFreeHeap(), + sdCardPresent() ? "OK" : "FAIL", + webSocket.connectedClients()); + } +}