/* * WiFi Handshake Capture - ESP32-C6 1.47" LCD * Multi-target capture: up to 3 networks per channel. * Green = pending, orange blink = active target, red = captured. */ #include "Display_ST7789.h" #include "LVGL_Driver.h" #include "WiFi_Scanner.h" #include "SD_Card.h" #include "HandshakeCapture.h" enum CaptureState { STATE_SCANNING, STATE_CAPTURING, STATE_WAITING }; CaptureState captureState = STATE_SCANNING; unsigned long capture_start_time = 0; const unsigned long CHANNEL_TIMEOUT_MS = 50000; // ~3 cycles (observe+deauth+capture) // ─── Live capture visual update ─── void updateCaptureVisuals() { static unsigned long last_vis = 0; static bool blink = false; unsigned long now = millis(); if (now - last_vis < 400) return; last_vis = now; blink = !blink; // Overall progress: captured / total WPA targets int captured = 0, total = 0; for (int i = 0; i < MAX_NETWORKS; i++) { if (networks[i].ssid.isEmpty()) break; if (!isCaptureable(i)) continue; total++; if (networks[i].handshake_captured) captured++; } Ui_SetProgress(captured, total); // Per-network visual state for (int i = 0; i < MAX_NETWORKS; i++) { if (networks[i].ssid.isEmpty()) break; // Is this network in an active capture slot? int si = -1; for (int s = 0; s < MAX_SLOTS; s++) { if (slots[s].active && slots[s].network_index == i) { si = s; break; } } char buf[48]; if (networks[i].handshake_captured) { // ✓ captured — red, static snprintf(buf, sizeof(buf), LV_SYMBOL_OK " %s", networks[i].ssid.c_str()); Ui_SetNetworkText(i, buf); Ui_SetNetworkColor(i, lv_palette_main(LV_PALETTE_RED)); } else if (si >= 0) { // ⚡ active target — orange, blinking CaptureSlot* slot = &slots[si]; if (capturePhase == PHASE_OBSERVING) { snprintf(buf, sizeof(buf), LV_SYMBOL_CHARGE " %s +%dc", slot->ssid, slot->client_count); } else { snprintf(buf, sizeof(buf), LV_SYMBOL_CHARGE " %s %d/2", slot->ssid, slot->eapol_count); } Ui_SetNetworkText(i, buf); lv_color_t color = blink ? lv_palette_main(LV_PALETTE_ORANGE) : lv_palette_darken(LV_PALETTE_ORANGE, 2); Ui_SetNetworkColor(i, color); } // else: pending — stays green from scan, no update needed } // Status line reflects current phase static CapturePhase last_phase = PHASE_CAPTURING; if (capturePhase != last_phase) { if (capturePhase == PHASE_OBSERVING) Ui_SetWifiStatus("Mapping clients..."); else Ui_SetWifiStatus("Capturing..."); last_phase = capturePhase; } static int last_eapol = -1; if (capturePhase == PHASE_CAPTURING && latest_eapol_count != last_eapol) { char ebuf[32]; snprintf(ebuf, sizeof(ebuf), "Ch %d " LV_SYMBOL_CHARGE " EAPOL %d", current_channel, latest_eapol_count); Ui_SetWifiStatus(ebuf); last_eapol = latest_eapol_count; } } // ─── Setup ─── void setup() { Serial.begin(115200); LCD_Init(); Set_Backlight(100); Lvgl_Init(); if (!SD_Init()) { Ui_SetWifiStatus("SD: no card"); } else { Ui_SetWifiStatus("SD OK"); } handshakeCaptureInit(); WiFiScanner_Refresh(); captureState = STATE_SCANNING; } // ─── Main loop ─── void loop() { Timer_Loop(); handshakeCaptureProcessPending(); handshakeCaptureLoop(); switch (captureState) { case STATE_SCANNING: { Ui_ShowProgress(false); if (getCaptureableCount() == 0) { Ui_SetWifiStatus("Rescan"); WiFiScanner_Refresh(); delay(500); break; } startMultiCapture(); if (is_capturing) { captureState = STATE_CAPTURING; capture_start_time = millis(); Ui_ShowProgress(true); Ui_SetWifiStatus("Mapping clients..."); } else { Ui_SetWifiStatus("No targets"); delay(1000); } break; } case STATE_CAPTURING: { updateCaptureVisuals(); bool any_active = false; for (int i = 0; i < MAX_SLOTS; i++) { if (slots[i].active) { any_active = true; break; } } if (!any_active && getCaptureableCount() == 0) { Ui_SetWifiStatus(LV_SYMBOL_OK " All done"); stopCapture(); captureState = STATE_SCANNING; delay(2000); } else if (!any_active) { stopCapture(); captureState = STATE_SCANNING; } else if (millis() - capture_start_time > CHANNEL_TIMEOUT_MS) { Ui_SetWifiStatus("Ch timeout"); stopCapture(); captureState = STATE_SCANNING; delay(2000); } break; } case STATE_WAITING: break; } delay(16); }